Home >Backend Development >PHP Tutorial >Using Eloquent Factories With PHPUnit Data Providers
or directly in a single test case. If you have a test case that needs to be tested against various data, you may need to use the Eloquent model and PHPUnit's data provider. setUp()
boots Laravel via TestCase
. The data providers are parsed very early during the run setUp()
, so if you want to use them, you will encounter the following error: 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()], ]; } }When running the above test you should get errors like the following, depending on the version of Laravel you are using - Here is the error I got on Laravel 11:
<code>$ vendor/bin/phpunit tests/Feature/ExampleTest.php There was 1 PHPUnit error: 1) Tests\Feature\ExampleTest::test_non_admin_users_cannot_access_admin The data provider specified for Tests\Feature\ExampleTest::test_non_admin_users_cannot_access_admin is invalid A facade root has not been set. tests/Feature/ExampleTest.php:18</code>This is because when the data provider code is running, the Laravel application has not started yet! If you are a Pest PHP user, the Bound Datasets example shows how to use closures for model data:
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']), ]);In PHPUnit, we can pass code to our tests through a data provider using closures without having to try to create data immediately:
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()], ]; } }Please note the
call, we pass it to $user()
. If you need to use the model in a different place, just assign it to a variable. Now, the factory data is created in testing, which is exactly what we want! To learn more about HTTP feature testing in Laravel, check out the documentation. actingAs()
The above is the detailed content of Using Eloquent Factories With PHPUnit Data Providers. For more information, please follow other related articles on the PHP Chinese website!