Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How can I test authorization logic in Laravel controllers
    Laravel authorization logic unit tests feature tests Laravel controllers Mockery Prophecy HTTP status codes user roles permissions access control


How can I test authorization logic in Laravel controllers


To test the authorization logic in your Laravel controllers, you can use a combination of unit tests and feature tests. Here's an example of how you can approach this:

1. Unit Tests:
- Create a test class for your authorization logic, such as `AuthorizationTest`.
- Use the `Mockery` or `Prophecy` library to mock the user's permissions or roles as needed for your test cases.
- Test the authorization methods in your controller, such as `authorize()` or `authorizeForUser()`.

Example:

php
   namespace Tests\Unit;

   use Mockery;
   use App\Http\Controllers\PostController;
   use Illuminate\Auth\Access\AuthorizationException;
   use Tests\TestCase;

   class AuthorizationTest extends TestCase
   {
       public function testUpdatePostAuthorization()
       {
           $user = Mockery::mock(\App\Models\User::class);
           $user->shouldReceive('can')->with('update', Mockery::any())->andReturn(true);

           $controller = new PostController();
           $controller->authorize('update', new \App\Models\Post());
           // No exception thrown, test passes
       }

       public function testUpdatePostAuthorizationFailure()
       {
           $this->expectException(AuthorizationException::class);

           $user = Mockery::mock(\App\Models\User::class);
           $user->shouldReceive('can')->with('update', Mockery::any())->andReturn(false);

           $controller = new PostController();
           $controller->authorize('update', new \App\Models\Post());
       }
   }
   

2. Feature Tests:
- Create a feature test class for your application's controllers, such as `PostControllerTest`.
- Use the `actingAs()` method to authenticate a user with specific permissions or roles.
- Verify the authorization behavior by asserting the appropriate HTTP status codes and responses.

Example:

php
   namespace Tests\Feature;

   use App\Models\User;
   use Illuminate\Foundation\Testing\RefreshDatabase;
   use Tests\TestCase;

   class PostControllerTest extends TestCase
   {
       use RefreshDatabase;

       public function testUpdatePostWithPermission()
       {
           $user = User::factory()->create();
           $user->givePermissionTo('update-post');

           $this->actingAs($user)
               ->put('/posts/1', ['title' => 'Updated Post'])
               ->assertStatus(302);
       }

       public function testUpdatePostWithoutPermission()
       {
           $user = User::factory()->create();

           $this->actingAs($user)
               ->put('/posts/1', ['title' => 'Updated Post'])
               ->assertStatus(403);
       }
   }
   

In the unit tests, you can mock the user's permissions and test the authorization methods directly in the controller. In the feature tests, you can create users with specific permissions and assert the appropriate HTTP responses based on the user's authorization.

By combining these two approaches, you can thoroughly test the authorization logic in your Laravel controllers, ensuring that the access control is working as expected.

Remember to also test edge cases, such as users with multiple roles, users with conflicting permissions, and scenarios where permissions might change during a user's session.

Citations:
[1] https://laravel.com/docs/5.1/authorization
[2] https://laravel.com/docs/11.x/authorization
[3] https://yajrabox.com/docs/laravel-acl/master/middleware
[4] https://geekytomato.com/user-roles-access-control-acl-laravel/
[5] https://github.com/kodeine/laravel-acl