高质量测试不是数量多,而是每条用例明确验证一个可观察行为变化;Laravel中应优先使用RefreshDatabase、actingAs()和单元测试规范,避免混淆测试层级与手动绕过框架机制。

高质量测试不是写得越多越好,而是每条用例都明确验证一个可观察的行为变化。Laravel 默认提供的 RefreshDatabase、工厂类和 HTTP 测试辅助方法已经覆盖了 80% 的真实场景,关键在于别绕开它们去“手动造数据”或“跳过认证逻辑”。
功能测试必须用 RefreshDatabase,别碰 DatabaseMigrations
功能测试里每次跑完都要确保数据库干净,RefreshDatabase 是唯一推荐方式。它底层是 TRUNCATE 所有表再重跑迁移,速度快、不破坏外键约束、也不执行 seeders(除非你显式调用 $this->seed())。
DatabaseMigrations 每次先 migrate:reset 再 migrate,在 CI 环境下容易因外键顺序或迁移依赖失败;本地开发时也明显更慢。如果你看到测试里用了 DatabaseMigrations,基本可以判定作者没认真读过 Laravel 文档的测试章节。
- 确认
phpunit.xml中DB_CONNECTION是sqlite且DB_DATABASE是:memory: - 测试类里只加
use RefreshDatabase;,别混用两个 trait - 不要在测试方法里手动
DB::table('users')->truncate()—— 这会绕过迁移定义的字段类型和约束
actingAs() 是 API 认证测试的唯一正解
测试带 auth:sanctum 或 auth:api 中间件的接口时,$this->actingAs($user, 'sanctum') 必须出现,且参数不能漏掉 guard 名。漏掉 guard 会导致请求走默认 web guard,而 web guard 不生成 token,结果就是 401 错误,但你根本没意识到是 guard 配错了。
常见错误现象:GET /api/user 返回 401,但 $user->tokens()->count() 是 0 —— 就是因为没传第二个参数。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- Sanctum 场景:用
$this->actingAs($user, 'sanctum') - Passport 场景:用
$this->actingAs($user, 'api') - 不要用
$this->withHeaders(['Authorization' => 'Bearer xxx'])手动塞 token,那是在模拟客户端,不是在测 auth 流程本身
单元测试里禁止出现 $this->get()、$this->post()
单元测试的目标是验证单个方法的输入输出,一旦出现 $this->get() 或 $this->post(),说明你正在写功能测试,只是放错了目录。这种混淆会导致两个问题:一是运行变慢(启动整个 HTTP 栈),二是掩盖了真正的依赖 —— 比如你本该 mock 一个第三方支付网关,结果却让它在测试里真调用。
正确做法:继承 PHPUnit\Framework\TestCase,而不是 Tests\TestCase;用 createMock() 或 Mockery::mock() 替代任何外部交互。
- 测试服务类、模型方法、帮助函数时,路径必须是
tests/Unit/ - 方法名以
test_开头,或加@test注释 - 如果发现某个单元测试里调用了
actingAs()或assertSee(),立刻把它移到tests/Feature/
测试命名要暴露失败时你能看到什么
像 test_user_can_login 这种名字毫无信息量。真正有用的命名应该包含断言点,比如 test_login_redirects_to_dashboard_on_success 或 test_login_returns_422_when_email_is_missing。这样 CI 失败时,光看方法名就知道哪条路径没走通,不用点进代码查。
更关键的是,这类命名会倒逼你写单一职责的测试:一个方法只验证一次 redirect、一次 status、一次数据库写入。很多人把五六条断言塞进一个测试方法,结果某天 assertStatus(302) 失败了,你得花两分钟确认到底是登录逻辑错、还是中间件配置错、还是路由改名了。
复杂点永远在边界条件 —— 比如邮箱格式错误时是否返回 JSON 结构一致?密码长度不足是否触发相同验证规则?这些不会在 happy path 里暴露,但用户一定会撞上。别让它们藏在“看起来差不多”的测试名后面。

















