Reputation: 2029
I am currently learning how to write PHPUnit test using a laravel app and hit a brick wall for some days now. My test was to allow only authenticated users update a book record if the user's id is the same as the book's user's id.
public function test_onlyAuthenticatedUserCanUpdateBookSuccessfully()
{
$user = factory(User::class)->create();
Passport::actingAs($user);
$book = factory(Book::class)->create();
dd($user, $book);
// $response = $this->json('PUT', '/api/books/'.$book->id, [
// 'id' => $book->id,
// 'title' => 'Updated book title',
// 'author'=> 'New Guy'
// ]);
// $response->assertStatus(201);
}
But I got a 403 error initially and while troubleshooting, i noticed from the dumped data that the created user's id is not the same as the book's user_id.
// Newly created user
#original: array:7 [
"name" => "Prof. Norwood Erdman"
"email" => "[email protected]"
"updated_at" => "2018-10-03 14:11:20"
"created_at" => "2018-10-03 14:11:20"
"id" => 2
]
// Newly created book
#attributes: array:6 [
"title" => "Quasi laudantium enim quas omnis."
"author" => "Mr. Jayson Roob"
"user_id" => 1
"updated_at" => "2018-10-03 14:11:20"
"created_at" => "2018-10-03 14:11:20"
"id" => 3
]
Going through my code, I discovered that every time a book is created the user_id will be set to 1 because my BooksFactory is using a hard coded value of user_id = 1
.
$factory->define(Book::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'author' => $faker->name,
'user_id' => 1
];
});
How can I write my code so that in my test when a book is created, the authenticated user's id is assigned as the book's user's id? I think that will fix the test. I am using sqlite memory database for test and not mysql.
Upvotes: 3
Views: 5256
Reputation: 35170
You can override attributes in a factory by passing an array to the create()
method with the attributes and values that you want to override:
$book = factory(Book::class)->create(['user_id' => $user->id]);
Furthermore, it might be a good idea to create create the user in the factory itself i.e.:
$factory->define(Book::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'author' => $faker->name,
'user_id' => function () {
return factory(App\User::class)->create()->id;
}
];
});
The reason the user_id
value in wrapped in a closure is to stop another user being created if you want to pass in your own id.
Overriding Attributes Documentation
Upvotes: 9
Reputation: 667
As a small update, for Laravel 8, the syntax would be:
$factory->define(Book::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'author' => $faker->name,
'user_id' => User::factory()->create()->id
];
});
Upvotes: 1