pest测试必须配置uses(tests\testcase::class)->in('feature', 'unit'),否则laravel测试辅助方法、数据库事务、模型事件等全部失效;自定义目录需同步更新in()参数,且testcase须继承illuminate\foundation\testing\testcase并含createsapplication。

直接用 it() 或 test() 就能跑通 Laravel 测试,但不配对 uses()、不处理认证上下文、不 fake 外部 HTTP 请求,测试大概率会失败或不可靠。
tests/Pest.php 里 uses() 调用是否正确
这是所有 Pest 测试生效的前提。Pest 不自动加载 Laravel 的测试环境,必须显式声明基类和作用域:
-
uses(Tests\TestCase::class)->in('Feature', 'Unit')是标配,漏掉任何一部分都会导致$this->get()、数据库事务、模型事件等全部失效 - 如果把测试文件放在
tests/Integration这类自定义目录下,->in()参数必须同步加上,否则 Pest 根本不识别该文件 -
Tests\TestCase必须继承Illuminate\Foundation\Testing\TestCase,且含use CreatesApplication—— 否则app()返回 null,服务容器未启动 - 别在测试文件里重复
require_once 'vendor/autoload.php',会破坏容器单例,引发奇怪的依赖绑定错误
API 测试中 auth:sanctum 怎么通过
直接 $this->getJson('/api/user') 必然返回 401,因为 Pest 不自动触发 Sanctum 中间件流程:
- 用
actingAs($user, 'sanctum'),不是actingAs($user)—— 第二个参数指定 guard 名,漏写就等于没登录 - 每次测试前都得调用一次
actingAs(),不能只在beforeEach()里设一次;连续测试中 token 会被复用,导致后续测试出现 419(CSRF)或 401 - 若用
api_token字段方案,需手动加 header:withHeader('Authorization', 'Bearer ' . $user->api_token) - 更稳妥的做法是在
beforeEach()里重置 Sanctum:Sanctum::actingAs($user),确保每次都是全新 token
assertJsonStructure 和 assertJson 的区别在哪
用错断言会导致“明明响应对了却报错”,或者“响应错了一堆字段却通过”:
-
assertJson(['name' => 'John'])只做浅层键值匹配,忽略多余字段、嵌套结构、字段顺序 —— API 响应含data包裹或分页meta时基本没用 -
assertJsonStructure(['data' => ['id', 'name'], 'meta' => ['per_page']])才是校验 API 响应结构的正解,它强制检查层级和必有字段 - 要验证某个字段**不存在**,优先用
assertJsonMissing(['deleted_at']),比assertJsonMissingExact()更宽容,避免因新增字段导致误失败 - 含时间戳、UUID 等动态字段时,别用
assertJson()做全量比对,改用json_decode($response->getContent(), true)提取后单独断言关键静态值
Http::fake() 为什么有时不生效
现象是测试里调用了外部 API,但 Http::fake() 没拦截,反而发出了真实请求:
- 只对 Laravel 的
HttpFacade 生效,如果被测代码用了new \GuzzleHttp\Client()或原生cURL,Http::fake()完全无效 - 通配符路径要写对:
'https://api.stripe.com/*'可以匹配/v1/payment_intents,但'api.stripe.com'(缺协议和通配符)就不行 - 必须在测试逻辑执行前调用,比如放在
it()闭包开头,而不是写在beforeEach()里再被覆盖 - 验证是否真发了请求,用
Http::assertSent(),别只信状态码;它能确认 URL、method、body 是否符合预期
最常被跳过的点:测试目录结构与 uses()->in() 不一致、Sanctum token 复用、以及用 assertJson() 替代 assertJsonStructure()。这三个地方一出错,测试就从“验证行为”退化成“碰运气”。











