logo
podcast Podcast
get help Get Unstuck

A strategy for testing permissions logic

And avoiding false positives

Joel Clermont
Joel Clermont
2024-04-19

In a previous tip, I talked about our typical approach for using roles and permissions in a Laravel app.

Today, I'm going to talk a little about how we test that permissions are being enforced properly.

One approach might be to create a user with no permissions, and then try to access a route that requires a specific permission. We could then assert that the user is rejected.

public function testCreateRequiresPermission(): void
{
    $user = $this->actingAs(User::factory()->create());
    // no permissions or role assigned
    
    $response = $this->get(route('some-route.create'));
    $response->assertForbidden();
}

This works, and it does make sure you're requiring a permission, but it is vague as to which specific permission is being tested against. A test like this might be passing for the wrong reason, without you knowing it.

Instead, an approach I prefer is to modify the role to remove just the one permission being tested:

public function testCreateRequiresPermission(): void
{
    $this->removePermissionFromRole(Permission::CREATE, Role::ADMIN);
    
    $user = $this->actingAs(User::factory()->create());
    $user->assignRole(Role::ADMIN);
    
    $response = $this->get(route('some-route.create'));
    $response->assertForbidden();
}

In this example, we're using a test helper method to remove one permission from an existing role definition for the duration of this one test. Then, we assign that modified role to the user, and we have absolute confidence that the test passes because that one specific permission is missing.

It's a small change, but it really boosts confidence in your tests.

Hope this helps,

Joel

P.S. If you're not testing your Laravel apps, get in touch, and we can help jump start your testing strategy.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼
email
No spam. Only real-world advice you can use.