'Laravel phpunit test failing authorization

I have a working api only application.

I am required to write a test decided to use laravel's phpunit test. This simple app allows only authenticated users can store, update or delete a book. Everyone else (authenticated or not) can retrieve a list of all books or view details of one book.

For my books test, I have written a test that first creates a user then a random token for the user. Then the token is passed using withHeaders when posting a new book record

class BooksTest extends TestCase
{
    public function test_onlyAuthenticatedUserCanAddBookSuccessfully()
    {
        $user = factory(User::class)->create();
        $token = str_random(10);
        $book = factory(Book::class)->create();

        $response = $this->withHeaders(['Authorization' => "Bearer $token"])
            ->json('POST', '/api/books', [
                'title' => 'book post',
                'author' => 'post author'
            ]);

        $response->assertStatus(201);
    }
}

Here I am using the default Laravel 5.6 UserFactory and my own BookFactory

$factory->define(Book::class, function (Faker $faker) {
    return [
        'title'     => $faker->sentence,
        'author'    => $faker->name,
        'user_id'   => 1
    ];
});

$factory->define(Rating::class, function (Faker $faker) {
    return [
        'user_id'   => 1,
        'book_id'   => mt_rand(1, 2),
        'rating'   => mt_rand(1, 5)
    ];
});

When I run the test, it fails and I get 401 instead of 200 which means the user is unauthorized.

I have a feeling that I have probably not set the $user in my test properly to be used during POST but I am not sure and really need help to get it right.



Solution 1:[1]

you can send headers in the fourth params of json() method as

$response = $this->json('POST', '/api/books', [
            'title' => 'book post',
            'author' => 'post author'
        ],['Authorization' => "Bearer $token"]);

since json method itself has provision to pass headers

or you can use post() method as

 $response = $this->post('/api/books', [
            'title' => 'book post',
            'author' => 'post author'
        ],['Authorization' => "Bearer $token"]);

Try this instead hope this solves your issues

Solution 2:[2]

Not sure how authentication is hooked on your application, but you could try this:

...

$this->actingAs($user)
    ->jsonPost('/api/books', [
        // ...  
    ]);

$response->assertStatus(201);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jayashree
Solution 2 Michael Grove