Courses

Testing in Laravel 12 For Beginners

Pest Datasets

Summary of this lesson:
- Using Pest datasets for test data variations
- Creating and using named datasets
- Implementing shared datasets across tests
- Working with Factory data in 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.

avatar

I needed to update the dataset code to get it to work.

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

avatar
You can use Markdown
avatar

Hello, does this mean we can use Pest and PHPUnit at the same time?

avatar

Yes, you can use pest and phpunit at the same time. But not in the same file/test.

avatar
You can use Markdown
avatar
You can use Markdown