pest 的简洁性在于去除胶水层,用 it() 和 describe() 直接表达测试意图;it() 与 test() 等价但更符合 bdd 风格;需显式使用 refreshdatabase::class,嵌套不宜超一层,运行单测须指定 php 文件路径。

直接用 it() 和 describe() 就能跑通 Laravel 测试,不需要写类、不用声明方法、不手动调 $this->get()——Pest 的简洁语法不是省几行代码,而是去掉所有和业务逻辑无关的胶水层。
it() 和 test() 的实际区别在哪
两者完全等价,it() 更贴近 BDD 描述风格(“it returns 200”),test() 更像传统命名(“test returns 200”)。Laravel 官方插件对两者一视同仁,底层都映射到同一个 PHPUnit 测试用例生成器。
- 选一个坚持用就行,混用不会报错,但团队内建议统一
-
it()在 Jetstream 等官方脚手架模板中默认使用,社区接受度更高 - 如果测试名含空格或特殊字符,必须用单引号包裹,例如
it('logs out when session expires', ...) - 函数体里不能直接用
$this;Laravel 插件已自动注入上下文,所以get('/')可以直接调,不用写$this->get('/')
describe() 嵌套层级别超过两层
describe() 是组织逻辑的利器,但嵌套过深会让测试文件难以定位和维护。Pest 不限制嵌套,但 Laravel 的测试运行器在报错时只显示最内层 it() 名称,外层 describe() 不参与错误路径展示。
- 推荐最多一层
describe()包裹多个it(),比如describe('User login flow', function () { it('...'); it('...'); }) - 两层嵌套(如
describe('API', function () { describe('v1', function () { it('...') }) }))会导致./vendor/bin/pest --list输出名称重复、难区分 - 想分组又怕混乱?改用目录结构:把相关测试拆到
tests/Feature/Auth/LoginTest.php、tests/Feature/Auth/LogoutTest.php,比嵌套更直观
uses() 比 setUp() 更轻量,但别漏掉 RefreshDatabase
uses() 是 Pest 推荐的共享设置方式,替代了 PHPUnit 中繁琐的 setUp() 方法。它本质是批量应用 Trait 或基类,但有个关键细节容易被忽略:Laravel 的数据库重置行为不会自动启用。
- 功能测试必须显式加
uses(RefreshDatabase::class),否则每次测试都会污染数据库状态 -
uses(TestCase::class)不是必须的——Pest 插件已默认继承Tests\TestCase,除非你要覆盖基类行为 - 多个 Trait 可以一起传:
uses(RefreshDatabase::class, WithoutMiddleware::class) - 如果用了
uses()却没加RefreshDatabase,测试可能偶然通过(比如前一个测试清了库),换环境就失败
运行单个测试时路径要写对,别依赖自动发现
Pest 确实会自动发现所有 *Pest.php 文件,但运行单个测试文件时,命令行参数必须指向具体 PHP 文件,而不是目录或模糊名。
- 正确:
./vendor/bin/pest tests/Feature/HomeTest.php - 错误:
./vendor/bin/pest HomeTest(找不到)、./vendor/bin/pest tests/Feature(报错:no tests found) - 想快速重跑上次失败的测试?用
./vendor/bin/pest --fail-fast,它不会跳过未改动的测试,但能提前终止 - watch 模式需要额外装
composer require --dev pestphp/pest-plugin-watch,光有--watch参数不生效
真正让 Pest “简洁”的,不是少写了 class 和 function 关键字,而是把每个测试用例还原成一句可验证的陈述——这要求你从命名开始就克制,不堆砌修饰词,不藏逻辑进嵌套里。越想写得“高级”,越容易掉进描述失焦、上下文泄漏、运行不可控的坑里。











