PHPUnit测试文件应放在tests/Feature或tests/Unit下,命名必须为*Test.php,类名须与文件名一致且继承TestCase;推荐起步用databaseMigrations(),需在发邮件前调用Mail::fake(),API测试遇419应加WithoutMiddleware或配置CSRF白名单。

PHPUnit测试文件该放哪、怎么命名
Laravel默认把测试放在 tests/Feature 和 tests/Unit 下,但不是随便放就能被自动识别。文件名必须以 Test.php 结尾,类名必须和文件名一致,且继承 TestCase 或其子类。
- 错误写法:
MyTest.php里定义class UserTest→ PHPUnit 找不到这个类 - 正确路径:
tests/Unit/UserTest.php,类名是UserTest extends TestCase - 运行时若提示
Class "UserTest" not found,先检查文件名+类名是否严格匹配 -
php artisan test默认只跑tests/下的*Test.php,别放进tests/Helpers这类自建目录里
用 refreshDatabase() 还是 databaseMigrations()
两者都清库,但机制不同,选错会导致测试变慢或数据残留。
-
refreshDatabase():每次测试前执行php artisan migrate:fresh,适合测试逻辑强依赖完整表结构(比如带外键、视图、索引)的场景;缺点是慢,尤其表多时 -
databaseMigrations():只回滚再重跑当前测试类里use DatabaseMigrations声明过的迁移,轻量但要求迁移文件稳定——如果迁移里有DB::table()->insert(),它不会重放 - 常见坑:在
setUp()里手动DB::table('users')->truncate(),结果和refreshDatabase()冲突,清库两次还报错 - 推荐起步用
databaseMigrations(),等测试变多、出现外键约束失败再切到refreshDatabase()
模拟 Mail::send() 时为什么收不到断言
直接调用 Mail::send() 不会触发真实发送,但也不会自动记录日志——得用 Mail::fake() 显式拦截。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 漏掉
Mail::fake():测试里调了Mail::to(...)->send(new WelcomeMail),但没 fake,断言Mail::assertSent(WelcomeMail::class)必然失败 - 顺序不能错:必须在发邮件前调用
Mail::fake(),写在test方法末尾无效 - 想验证发给谁、带什么数据?用
Mail::assertSent(WelcomeMail::class, function ($mail) { return $mail->hasTo('test@example.com'); }) - 注意:fake 后真实 SMTP 配置失效,不用关
MAIL_MAILER=smtp,但也不用配账号密码
测试 API 接口时 $this->postJson() 返回 419
Laravel 8+ 默认开启 CSRF 保护,而 postJson() 不自动带 X-XSRF-TOKEN,导致中间件拦截。
立即学习“PHP免费学习笔记(深入)”;
- 最简解法:在测试类顶部加
use WithoutMiddleware;,跳过所有中间件(包括VerifyCsrfToken) - 更贴近真实:保留中间件,改用
$this->withSession(['_token' => 'test-token'])->postJson(...),但需手动构造 token - 别在
phpunit.xml里关APP_DEBUG=false来“绕过”419——这只是掩盖问题,实际线上仍会出错 - 如果接口本就该开放给前端(比如登录),建议在
app/Http/Middleware/VerifyCsrfToken.php的$except加上对应路由,测试自然通过
真实项目里,测试失败往往卡在环境假设和实际行为不一致的地方:比如以为数据库空着,其实 migration 没跑;以为邮件发出去了,其实根本没 fake;以为 token 自动带上,其实 CSRF 拦了。盯住这些“默认不生效”的环节,比堆断言更重要。


















