Laravel怎么写单元测试_Laravel如何使用Pest测试框架【指南】

2次阅读

laravel 中运行首个 pest 测试需先确保 phpunit 环境,执行 composer require –dev pestphp/pest pestphp/pest-plugin-laravel,再运行 php artisan pest:install 生成配置和测试目录,最后用 ./vendor/bin/pest 或 php artisan test 启动。

Laravel怎么写单元测试_Laravel如何使用Pest测试框架【指南】

怎么在 Laravel 里跑起第一个 Pest 测试

Pest 是 Laravel 官方推荐的测试框架,本质是 PHPUnit 的轻量封装,但写法更简洁。它不是独立安装的“新东西”,而是基于 PHPUnit 构建的 DSL 层——所以你得先有 PHPUnit 环境,再装 Pest。

  • composer require --dev pestphp/pest pestphp/pest-plugin-laravel 安装(注意:Laravel 10+ 默认已预装 pest 命令,但插件仍需手动加)
  • 运行 php artisan pest:install 生成配置和基础测试目录(会创建 tests/Pest.phptests/Feature / tests/Unit
  • 别直接删掉 tests/TestCase.php ——Pest 会自动加载它,里面定义的 uses(TestsTestCase::class) 是关键,否则数据库事务、http 辅助方法全失效
  • 首次运行 ./vendor/bin/pestphp artisan test,看到绿色点就说明通了

测试 Model 时为什么 save() 不触发事件或软删除

常见现象:写了个 it('soft deletes user'),调用 $user->delete() 后查数据库发现记录没进 deleted_at,或者观察者里的 creating 根本没执行。

  • 根本原因是 Pest 默认不启动 Laravel 应用上下文 —— 即使用了 uses(TestsTestCase::class),也得确保测试类继承PestTest(由 pest:install 自动处理),否则 Laravel 的服务容器、模型事件监听器、软删除 trait 都不会注册
  • 检查 tests/Pest.php 是否包含 uses(TestsTestCase::class)->in('Feature', 'Unit');;如果手动新建了测试文件在 tests/Unit 外,它不会被自动挂载
  • Model 测试建议放 tests/Unit,但必须用 RefreshDatabaseDatabaseTransactions trait(在 TestCase 里已配好),否则事务不生效,assertDatabaseMissing 类断言会失败

it('calls webhook') 怎么避免真实 HTTP 请求

写 Feature 测试时调用 Http::post() 或 Guzzle 直连外部服务,会导致测试慢、不稳定、依赖网络,还可能触发真实支付或通知。

  • 用 Laravel 内置的 Http::fake(),不是 Mockery 也不是 MockHttpClient ——后者是低层抽象,容易漏掉响应结构
  • 在测试开头加 Http::fake(['https://api.example.com/*' => Http::response(['ok' => true], 200)]);,路径支持通配符,响应可带 json、headers、status
  • 如果被测代码用了 new Client() 或第三方 SDK(比如 Stripe SDK),Http::fake() 不生效 —— 得换用 Http::preventStrayRequests() 配合真实 mock,或改用 SDK 自带的测试模式(如 Stripe::setApiKey('sk_test_...') + Stripe::setApiBase('http://localhost')
  • 别忘了验证是否真的发了请求:Http::assertSent(function (Request $request) { return $request->url()->host() === 'api.example.com'; });

为什么 php artisan test --Filter=FooTest 找不到测试

运行单个测试时提示 “No tests executed”,或报错 Class 'TestsFooTest' not found,通常不是 Pest 问题,而是命名与文件结构不匹配。

  • Pest 测试文件名必须是 *Test.php(如 UserTest.php),且类名要严格对应:文件 UserTest.php → 类 UserTest命名空间 TestsUnit(或 TestsFeature
  • 如果你用的是纯函数式写法(即没写 class UserTest),那不能用 --filter 按类名过滤 —— Pest 的 --filter 只认 PHPUnit 兼容的类/方法名,函数式测试只能用 --grep(如 php artisan test --grep="creates user"
  • 运行 ./vendor/bin/pest --list-tests 查看实际识别到的测试名,比猜路径更可靠
  • windows 下注意路径分隔符,--filter 中的反斜杠可能被转义,优先用正斜杠或双引号包裹

最常被忽略的一点:Pest 的函数式测试(it('does something'))不生成类,所以 ide 跳转、静态分析、部分 CI 工具对它的支持弱于传统 PHPUnit 类写法。真要团队长期维护,别只图写得快。

text=ZqhQzanResources