在 PHPUnit 数据提供器中使用 Eloquent 工厂
发布于 作者 Paul Redmond
在功能测试中使用 Laravel 工厂有几种方法,例如在 `setUp()` 中创建模型,以便在多个测试中使用它,或者直接在单个测试用例中创建。如果您有一个测试用例,您希望针对各种数据进行测试,您可能想使用 PHPUnit 的 数据提供器 和 Eloquent 模型。
在功能测试中使用数据提供器可能会遇到问题,因为它们在 Laravel 通过框架的 `TestCase` 启动之前运行(`setUp()` 期间运行)。数据提供器在运行 `phpunit` 过程的早期被解析,因此,如果您想使用它们,您会遇到以下错误
<?php namespace Tests\Feature; use App\Models\User;use Illuminate\Foundation\Testing\RefreshDatabase;use PHPUnit\Framework\Attributes\DataProvider;use Tests\TestCase; class ExampleTest extends TestCase{ use RefreshDatabase; #[DataProvider('nonAdminUsers')] public function test_non_admin_users_cannot_access_admin($user): void { $response = $this ->actingAs($user()) ->get('/admin') ->assertStatus(403); } public static function nonAdminUsers(): array { return [ [User::factory()->player()->create()], [User::factory()->coach()->create()], [User::factory()->owner()->create()], ]; }}
如果您运行上面的测试,您应该会收到类似于以下的错误,具体取决于您使用的 Laravel 版本——以下是我在 Laravel 11 上得到的错误
$ vendor/bin/phpunit tests/Feature/ExampleTest.php There was 1 PHPUnit error: 1) Tests\Feature\ExampleTest::test_non_admin_users_cannot_access_adminThe data provider specified for Tests\Feature\ExampleTest::test_non_admin_users_cannot_access_admin is invalidA facade root has not been set. tests/Feature/ExampleTest.php:18
这是因为当数据提供器代码运行时,Laravel 应用程序尚未启动!如果您是 Pest PHP 用户,Bound Datasets 示例说明了使用闭包来获取模型数据
it('can generate the full name of a user', function (User $user) { expect($user->full_name)->toBe("{$user->first_name} {$user->last_name}");})->with([ fn() => User::factory()->create(['first_name' => 'Nuno', 'last_name' => 'Maduro']), fn() => User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Downing']), fn() => User::factory()->create(['first_name' => 'Freek', 'last_name' => 'Van Der Herten']),]);
在 PHPUnit 中,我们可以使用闭包将代码通过数据提供器传递给我们的测试,而不会立即尝试创建数据
namespace Tests\Feature; use App\Models\User;use Illuminate\Foundation\Testing\RefreshDatabase;use PHPUnit\Framework\Attributes\DataProvider;use Tests\TestCase; class ExampleTest extends TestCase{ use RefreshDatabase; #[DataProvider('nonAdminUsers')] public function test_non_admin_users_cannot_access_admin($user): void { $response = $this ->actingAs($user()) ->get('/admin') ->assertStatus(403); } public static function nonAdminUsers(): array { return [ [fn(): User => User::factory()->player()->create()], [fn(): User => User::factory()->coach()->create()], [fn(): User => User::factory()->owner()->create()], ]; }}
请注意 `$user()` 调用,我们将其传递给 `actingAs()`。如果您需要在不同的地方使用模型,只需将其分配给一个变量即可。现在,工厂数据是在测试中创建的,这正是我们想要的!要了解有关 Laravel 中的 HTTP 功能测试的更多信息,请查看 文档。