Someone in the Mastering Laravel community was running into an issue with factories where every once in a while, two models would be created with the same value for a property, and this would lead to a flaky test failure.
The question was: how can we prevent these occasional test failures?
The short answer is to use the unique()
modifier that Faker provides to prevent these values from colliding, but there's a more nuanced answer that I want to share.
Let's make it a tangible example, so we can discuss it more clearly. We have a User
model with first_name
and last_name
properties.
And in only one or two tests, we need to make sure our factory generates unique values for those properties.
I would not recommend chaining unique()
on those properties in the default factory definition.
Why? Only a couple tests need uniqueness, and adding this modifier adds some overhead to every usage.
I'd only add unique()
to the default definition if the database schema enforced uniqueness. Then it's a core application requirement.
So what would I do instead? If it's just one or two tests, I'd do it right inside the test when calling the factory:
User::factory()->create([
'first_name' => $this->faker->unique()->firstName,
'last_name' => $this->faker->unique()->lastName,
]);
If this is something needed in more than a handful of tests, I might go a step further and create a new state in my factory:
// in UserFactory.php
public function uniqueNames()
{
return $this->state([
'first_name' => $this->faker->unique()->firstName,
'last_name' => $this->faker->unique()->lastName,
]);
}
// then in my test
User::factory()->uniqueNames()->create();
Here to help,
Joel
P.S. I bet you knew I was going to recommend that you should check out the Mastering Laravel community. Well, you should!