Laravel怎么编写单元测试_Laravel Testing入门指南【保障】

1次阅读

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

Laravel怎么编写单元测试_Laravel Testing入门指南【保障】

test 方法里 assert 为什么总报错“Expected status code 200, got 500”

因为 Laravel 的测试默认不加载 .env 文件,数据库连接、缓存驱动、APP_KEY 等全按 phpunit.xml 里配置走——而你本地开发环境的 .env 很可能没同步到测试环境,导致 DB 连不上或加密失败。

  • 检查 phpunit.xmlAPP_ENV 是否设为 testing,且 DB_CONNECTION 指向 sqlite 或已配好的测试专用数据库
  • 别在 .env 里改测试配置;所有测试专属设置应写进 phpunit.xml<env></env> 节点,比如:
    <env name="DB_DATABASE" value=":memory:"/>
  • 如果用 :memory: SQLite,记得在 TestCase.phpsetUp() 里调用 $this->artisan('migrate');,否则表不存在直接 500

怎么测带 Auth 的控制器,避免 “Unauthenticated”

Laravel 测试里不会自动登录用户,actingAs() 是最轻量也最容易漏掉的关键步骤。

  • 不要依赖 sessioncookie;一律用 $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 文件,或用 DatabaseMigrations trait 配合 seeders
  • 注意 factory 的 state()for() 用法差异:关联模型要用 for(User::factory()),不是 user_id => User::factory()->create()->id,后者会逃逸出事务

测试里最麻烦的永远不是写断言,而是让环境和数据状态跟生产一致——哪怕只是多一个未提交的 migration,或者 config/cache 没清干净,都会让 assert 看似随机失败。

text=ZqhQzanResources