All-in-One Tests: PHPUnit Data Providers and Pest Datasets

When writing automated tests, sometimes you want to repeat the same test multiple times on various data inputs. In Laravel, you can do this easily with data providers and datasets. I will show you a PHPUnit and a Pest example.

Let's say we have this Controller with the validation:

class CreateTaskController extends Controller
{
public function __invoke(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'subtasks' => ['required', 'array'],
'subtasks.*.name' => ['required', 'string', 'max:255'],
'subtasks.*.is_completed' => ['required', 'boolean'],
'subtasks.*.due_date' => ['required', 'date'],
]);
 
// ... saving the task

And then, we want to test that, with different input data, we have different validation errors.

class TaskCreationTest extends TestCase
{
public function test_cannot_save_task_without_name() {
$this->postJson(route('task.store'), [
'subtasks' => [
[
'name' => 'Subtask 1',
'is_completed' => false,
'due_date' => '2024-01-01',
],
],
])
->assertStatus(422)
->assertJsonValidationErrorFor('name');
}
 
public function test_cannot_save_task_without_subtasks() {
$this->postJson(route('task.store'), [
'name' => 'Task 1',
])
->assertStatus(422)
->assertJsonValidationErrorFor('subtasks');
}
 
// ... other test methods for other fields

But wouldn't it be cool to have ONE method instead? To not copy-paste the same test method into another one just to assert different statuses for a different data set?

Here's how you can do it: by specifying @dataProvider and a separate method that returns...

The full tutorial [5 mins, 910 words] is only for Premium Members

Login Or Become a Premium Member for $129/year or $29/month
What else you will get:
  • 58 courses (1056 lessons, total 44 h 09 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials