In a previous tip, I shared our approach to testing validation logic, including how we name the validation tests. Today I want to focus on the specific assertions we make when testing validation logic.
Laravel provides a nice testing helper to assert that a specific field has a validation error:
// inside our test
$response->assertSessionHasErrors([
'first_name',
'last_name',
'email',
]);
This lets me assert that all three of these fields failed validation logic. This is a good start, but it's not quite enough.
Why? Well fields have more than one validation rule attached to them. Continuing our example, the first_name
field would have
rules for string
, required
, and max:255
. This is a pretty basic example, but it illustrates the point.
With our assertion above, we don't actually know which of these rules failed, just that any one of them did.
How can we make this a stronger test? We can assert the specific error message:
// inside our test
$response->assertSessionHasErrors([
'first_name' => 'The first name field is required.',
'last_name' => 'The last name field is required.',
'email' => 'The email field is required.',
]);
Now I have confidence that all three of these fields specifically failed the required
validation rule.
This is important to me, especially as the rules get more complicated than our admittedly basic example here.
I've heard some objections to this approach, mostly around the idea that the error messages are subject to change.
It's true, this test is a bit brittle to changes in how Laravel words the error message. And yes, they do change from time to time.
But honestly, it's not a big deal. A few quick "find and replace" commands later, and all the tests are passing again.
If Laravel provided a better way of doing this, for example letting me assert directly which rule failed like Livewire does, I'd switch to that immediately. But until then, this approach gives me a lot more confidence for very little extra effort.
Here to help,
Joel
P.S. I know what you're thinking: this guy sure does think about validation a lot. It's true. Aaron and I even wrote a whole book on Laravel validation rules.