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...