Back to Course |
Testing in Laravel 11 For Beginners

Pest Datasets

In this section of the course, we will cover a few additional Pest functions that are not available in the same way in PHPUnit, or just work differently.

Topic of this lesson is datasets.

With datasets, you define an array of data and run tests multiple times with different subset of that data. Another use-case is to assign a name to a specific dataset and use it in multiple locations.


How to Use Datasets

Datasets are defined using the with() method and providing arguments in the function. Let's change the create product test to use the dataset.

tests/Feature/ProductsTest.php:

test('create product successful', function ($name, $price) {
$product = [
'name' => 'Product 123',
'price' => 1234
];
 
asAdmin()
->post('/products', $product)
->post('/products', ['name' => $name, 'price' => $price])
->assertStatus(302)
->assertRedirect('products');
 
$this->assertDatabaseHas('products', $product);
$this->assertDatabaseHas('products', ['name' => $name, 'price' => $price]);
 
$lastProduct = Product::latest()->first();
expect($name)->toBe($lastProduct->name)
->and($price)->toBe($lastProduct->price);
expect($product['name'])->toBe($lastProduct->name)
->and($product['price'])->toBe($lastProduct->price);
})->with([
['Product 1', 123],
['Product 2', 456],
]);

After running the test, we can see it is run two times, and the test adds to a name.

Every dataset can be assigned a name by adding a key to the array.

tests/Feature/ProductsTest.php:

test('create product successful', function ($name, $price) {
asAdmin()
->post('/products', ['name' => $name, 'price' => $price])
->assertStatus(302)
->assertRedirect('products');
 
$this->assertDatabaseHas('products', ['name' => $name, 'price' => $price]);
 
$lastProduct = Product::latest()->first();
expect($name)->toBe($lastProduct->name)
->and($price)->toBe($lastProduct->price);
})->with([
'test 1' => ['Product 1', 123],
'test 2' => ['Product 2', 456],
]);

Now, when the test is run, the name of the dataset is being used.


Shared Datasets

Datasets can be shared. First, we need to create a dataset file to create shared datasets. This can be done using an artisan command.

php artisan pest:dataset Products

Datasets are created in the tests/Datasets folder.

In the dataset, we provide its name and data in the array.

tests/Datasets/Products.php:

dataset('products', [
[['name' => 'Product 1', 'price' => 123]],
[['name' => 'Product 2', 'price' => 453]],
]);

In the test dataset, products can be called within the with() function.

tests/Feature/ProductsTest.php:

test('create product successful', function ($product) {
asAdmin()
->post('/products', ['name' => $name, 'price' => $price])
->post('/products', $product)
->assertStatus(302)
->assertRedirect('products');
 
$this->assertDatabaseHas('products', ['name' => $name, 'price' => $price]);
$this->assertDatabaseHas('products', $product);
 
$lastProduct = Product::latest()->first();
expect($name)->toBe($lastProduct->name)
->and($price)->toBe($lastProduct->price);
expect($product['name'])->toBe($lastProduct->name)
->and($product['price'])->toBe($lastProduct->price);
})->with([
['Product 1', 123],
['Product 2', 456],
]);
})->with('products');


Datasets with Factories

Datasets can have data created from a factory within a closure.

tests/Datasets/Products.php:

use App\Models\Product;
 
dataset('products', [
[['name' => 'Product 1', 'price' => 123]],
[['name' => 'Product 2', 'price' => 453]],
]);
 
dataset('create product', [
fn() => Product::factory()->create(),
]);

We can reuse datasets in more than one test.

tests/Feature/ProductsTest.php:

test('product edit contains correct values', function ($product) {
$product = Product::factory()->create();
 
asAdmin()->get('products/' . $product->id . '/edit')
->assertStatus(200)
->assertSee('value="' . $product->name . '"', false)
->assertSee('value="' . $product->price . '"', false)
->assertViewHas('product', $product);
})->with('create product');
 
test('product update validation error redirects back to form', function ($product) {
$product = Product::factory()->create();
 
asAdmin()->put('products/' . $product->id, [
'name' => '',
'price' => ''
])
->assertStatus(302)
->assertInvalid(['name', 'price'])
->assertSessionHasErrors(['name', 'price']);
})->with('create product');

More about datasets can be found in the official Pest documentation.