Our Laravel app uses PostgreSQL and before we insert a register in a table we reserve the next valid id by calling PostgreSQL nextval
function.
I want to test the insert
method of UserRepository
. As our database expects to receive an id I would need to generate it also in the test method that tests the insert
method, so I use Laravel's factories make
method like this to create a fake id:
$userModel = UserModel::factory()->make([
'id' => $this->userRepository->nextValId()
// Another solution 'id' => $this->faker->unique()->randomNumber(5)
]);
$this->userRepository->insert($userModel->toArray());
This might not seem too complex, but imagine I now have an insertMany
method that inserts several users at once, and I want to test this insertMany
method. In this case the creation with Laravel's factory()
gets more complicated. To start off, this code wouldn't work now as the ids of all users would be the same:
$collection = UserModel::factory(4)->make([
'id' => $this->userRepository->nextValId()
// Another solution 'id' => $this->faker->unique()->randomNumber(5)
]);
$this->userRepository->insertMany($collection->toArray());
So I have to rewrite it like this:
$collection = UserModel::factory(4)->make();
$users = $collection->toArray();
$users[0]['id'] = $this->userRepository->nextValId();
$users[1]['id'] = $this->userRepository->nextValId();
$users[2]['id'] = $this->userRepository->nextValId();
$users[3]['id'] = $this->userRepository->nextValId();
$this->userRepository->insertMany($users);
So the question is: is there a one-liner for this use case? Is there a way to tell inside the array of the make
that a key has to be different for every model created by the factory? (In this case, I would want $this->userRepository->nextValId()
to act for each one of the models created.)
Of course I do not consider using Laravel's factories create
method as it would create the register already in the database table and the later insertion would throw a duplicate key exception.
Side note: this is a fake example, not real, so it is possible that there might be a little bug. The code pasted is not proved. Mine is different, but the idea is the same as the one in the example used.
I have found a solution using Laravel's factory sequences: https://laravel.com/docs/9.x/database-testing#sequences
This would be the cleanest code in my opinion: