laravel测试报500因未加载.env,需在phpunit.xml配置app_env=testing及db_database=:memory:并迁移;测auth需actingas();http::fake()仅拦截laravel http门面;factory数据在事务中自动回滚。

test 方法里 assert 为什么总报错“Expected status code 200, got 500”
因为 Laravel 的测试默认不加载 .env 文件,数据库连接、缓存驱动、APP_KEY 等全按 phpunit.xml 里配置走——而你本地开发环境的 .env 很可能没同步到测试环境,导致 DB 连不上或加密失败。
- 检查
phpunit.xml中APP_ENV是否设为testing,且DB_CONNECTION指向sqlite或已配好的测试专用数据库 - 别在
.env里改测试配置;所有测试专属设置应写进phpunit.xml的<env></env>节点,比如:<env name="DB_DATABASE" value=":memory:"/> - 如果用
:memory:SQLite,记得在TestCase.php的setUp()里调用$this->artisan('migrate');,否则表不存在直接 500
怎么测带 Auth 的控制器,避免 “Unauthenticated”
Laravel 测试里不会自动登录用户,actingAs() 是最轻量也最容易漏掉的关键步骤。
- 不要依赖 session 或 cookie;一律用
$user = User::factory()->create(); $this->actingAs($user); - 如果测试需要特定权限(比如 admin),别只设
role字段,要确保中间件或策略实际能识别它——常见坑是用了包(如 spatie/laravel-permission)但没在测试里syncPermissions - 用
$this->withoutMiddleware()可临时跳过验证,但仅限调试;真实业务逻辑必须覆盖带 auth 的完整链路
mock 一个外部 HTTP 请求,为什么 Http::fake() 没生效
因为 Http::fake() 只拦截通过 Laravel 的 Http facade 发出的请求,如果你在代码里写了 file_get_contents()、curl 或第三方 SDK(比如 Guzzle 直接 new Client),它完全无感。
- 确认被测代码真正在用
Http::get()等方法;否则得换方案:对 Guzzle,用Http::fake()不行,得 mock 它的HandlerStack - fake 响应时别只写字符串,用数组或
Response::make()更稳,比如:Http::fake(['api.example.com' => Http::response(['data' => 'ok'], 200)]); - 如果测试里调了多次相同 URL,记得用闭包形式 fake,否则第二次请求会拿不到响应体
测试数据库迁移后数据不对,factory 生成的数据哪去了
因为 Laravel 默认每个测试方法运行在独立事务里(RefreshDatabase trait),事务回滚后 factory 写入的数据就没了——但 migration 是在事务外执行的,表结构留着,数据清空了。
- 别在
setUp()里手动DB::table()->insert();所有测试数据都交给 factory +create(),它们会随事务一起回滚 - 如果测试需要「预置状态」(比如系统默认分类),把 insert 逻辑放进 migration 文件,或用
DatabaseMigrationstrait 配合seeders - 注意 factory 的
state()和for()用法差异:关联模型要用for(User::factory()),不是user_id => User::factory()->create()->id,后者会逃逸出事务
测试里最麻烦的永远不是写断言,而是让环境和数据状态跟生产一致——哪怕只是多一个未提交的 migration,或者 config/cache 没清干净,都会让 assert 看似随机失败。