Datasets

With datasets, you can define an array of test data and Pest will run the same test for each set automatically. This saves time and effort by eliminating the need to repeat the same test manually with different data.

1it('has emails', function (string $email) {
2 expect($email)->not->toBeEmpty();
3})->with(['enunomaduro@gmail.com', 'other@example.com']);

When running your tests, Pest will automatically add informative test descriptions to tests that use datasets, outlining the parameters used in each test, aiding in understanding the data and identifying issues if a test fails.

Naturally, it is possible to supply multiple arguments by providing an array containing arrays of arguments.

1it('has emails', function (string $name, string $email) {
2 expect($email)->not->toBeEmpty();
3})->with([
4 ['Nuno', 'enunomaduro@gmail.com'],
5 ['Other', 'other@example.com']
6]);

To manually add your own description to a dataset value, you may simply assign it a key.

1it('has emails', function (string $email) {
2 expect($email)->not->toBeEmpty();
3})->with([
4 'james' => 'james@laravel.com',
5 'taylor' => 'taylor@laravel.com',
6]);

If a key is added, Pest will use the key when generating the description for the test.

It is important to notice that when using closures in your dataset, you must declare the arguments type in the closure passed to the test function.

1it('can sum', function (int $a, int $b, int $result) {
2 expect(sum($a, $b))->toBe($result);
3})->with([
4 'positive numbers' => [1, 2, 3],
5 'negative numbers' => [-1, -2, -3],
6 'using closure' => [fn () => 1, 2, 3],
7]);

Bound Datasets

Pest's bound datasets can be used to obtain a dataset that is resolved after the beforeEach() method of your tests. This is particularly useful in Laravel applications (or any other Pest integration) where you may need a dataset of App\Models\User models that are created after your database schema is prepared by the beforeEach() method.

1it('can generate the full name of a user', function (User $user) {
2 expect($user->full_name)->toBe("{$user->first_name} {$user->last_name}");
3})->with([
4 fn() => User::factory()->create(['first_name' => 'Nuno', 'last_name' => 'Maduro']),
5 fn() => User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Downing']),
6 fn() => User::factory()->create(['first_name' => 'Freek', 'last_name' => 'Van Der Herten']),
7]);

If you want, you can bind a single argument to the test case. However, Pest requires that it must be fully typed in the it|test function arguments.

1-it('can generate the full name of a user', function ($user, $fullName) {
2+it('can generate the full name of a user', function (User $user, $fullName) {
3 expect($user->full_name)->toBe($fullName);
4})->with([
5 [fn() => User::factory()->create(['first_name' => 'Nuno', 'last_name' => 'Maduro']), 'Nuno Maduro'],
6 [fn() => User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Downing']), 'Luke Downing'],
7 [fn() => User::factory()->create(['first_name' => 'Freek', 'last_name' => 'Van Der Herten']), 'Freek Van Der Herten'],
8]);

Sharing Datasets

By storing your datasets separately in the tests/Datasets folder, you can easily distinguish them from your test code and ensure that they do not clutter your main test files.

1// tests/Unit/ExampleTest.php...
2it('has emails', function (string $email) {
3 expect($email)->not->toBeEmpty();
4-})->with(['enunomaduro@gmail.com', 'other@example.com']);
5+})->with('emails');
6 
7// tests/Datasets/Emails.php...
8+dataset('emails', [
9+ 'enunomaduro@gmail.com',
10+ 'other@example.com'
11+]);

Bound datasets, description keys, and other rules that are applicable to inline datasets can also be applied to shared datasets.

Scoped Datasets

Occasionally, datasets may pertain only to a specific feature or set of folders. In such cases, rather than distributing the dataset globally within the Datasets folder, you can generate a Datasets.php file within the relevant folder requiring the dataset and restrict the dataset's scope to that folder alone.

1// tests/Feature/Products/ExampleTest.php...
2it('has products', function (string $product) {
3 expect($product)->not->toBeEmpty();
4})->with('products');
5 
6// tests/Feature/Products/Datasets.php...
7dataset('products', [
8 'egg',
9 'milk'
10]);

Combining Datasets

You can easily obtain complex datasets by combining both inline and shared datasets. When doing so, the datasets will be combined using a cartesian product approach.

In the following example, we verify that all of the specified businesses are closed on each of the provided weekdays.

1dataset('days_of_the_week', [
2 'Saturday',
3 'Sunday',
4]);
5 
6test('business is closed on day', function(string $business, string $day) {
7 expect(new $business)->isClosed($day)->toBeTrue();
8})->with([
9 Office::class,
10 Bank::class,
11 School::class
12])->with('days_of_the_week');

When running the example above, Pest's output will contain a description of each of the validated combinations.

Repeating Tests

In some cases, you may need to repeat a test multiple times for debugging purposes or to ensure that the test is stable. On these occasions, you may use the repeat() method to repeat a test a given number of times.

1it('can repeat a test', function () {
2 $result = /** Some code that may be unstable */;
3 
4 expect($result)->toBeTrue();
5})->repeat(100); // Repeat the test 100 times

After becoming skilled at utilizing datasets for testing, the next crucial step is to gain an understanding of how to test for exceptions. This involves verifying that your code behaves correctly and throws appropriate exceptions when it encounters unexpected or erroneous input: Exceptions →