Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

fabianmu's avatar

Mocking Gate/GateContract

I am strugling on how to mock permissions that I've setup according to the laracast ACL in Laravel: Roles and Permissions.

Since AuthServiceProvider@getPermissions does not return any permissions from the DB when running the tests, it's obvious that I can also not take the permissions into account when testing.
Hence, I'd like to mock the Gate Facade, however I have no idea how to do that and would be happy for some help.

For some context, see my AuthServiceProvider.php

<?php

namespace App\Providers;

use App\Permission;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Cache;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        parent::registerPolicies($gate);

        // Dynamically register permissions with Laravel's Gate.
        foreach ($this->getPermissions() as $permission) {
            $gate->define($permission->name, function ($user) use ($permission) {
                return $user->hasPermission($permission);
            });
        }
    }

    protected function getPermissions()
    {

        // if running tests, this will be called before migrations are run, thus,  there won't be a `permission` table and eloquent will throw and Exception
        // catching the Exception to return an empty array of `permissions`in order for laravel to keep on booking when running tests
        try {
            return Cache::remember("auth.permissions", 10, function () {
                return Permission::with('roles')->get();
            });
        } catch (\Exception $e) {
            return [];
        }
    }
}
0 likes
7 replies
bigbing's avatar

Hi Fabian, the below code is working fine for me:

public function boot(GateContract $gate)
{
    parent::registerPolicies($gate);

    foreach ($this->getPermissions() as $permission) {

       //dd($this->getPermissions());
       
       $gate->define($permission->name, function($user) use ($permission) {

            //dd($user->hasRole($permission->roles));
            return $user->hasRole($permission->roles);
        });           
    }
}

protected function getPermissions() 
{
    return Permission::with('roles')->get();
}

If you can implement this and solve your issues, please let me know. i would love to see some sample app implementation.

fabianmu's avatar

Thanks, that's how my implementation does it as well, except that I check for hasPermission instead of hasRole. It all works fine outside of tests, this is the gist which I use. However, as stated in my initial comment, the Gate is not aware of the Permissions (since there are none) when running tests and I'm looking for a way how to Mock the Gate.

3 likes
bigbing's avatar

Great.. i would love to see your implementation.

Belio's avatar

Maybe a bit late but I solved the testing problem moving the logic to a class.


// AuthServiceProvider

public function boot()
{
    $this->registerPolicies();
    RolePolicies::define();
}


//RolePolicies

class RolePolicies
{
    public static function define()
    {
        foreach (self::getPermissions() as $permission) {
            Gate::define($permission->name, function($user) use ($permission) {
                return $user->hasRole($permission->roles);
            });
        }
    }

    protected static function getPermissions()
    {
        try {
            return Permission::with('roles')->get();
        } catch (\Exception $e) {
            return [];
        }
    }
}

// Test

/** @test */
public function a_user_cannot_use_not_allowed_resources()
{
    $user = factory(User::class)->create();
    $role = factory(Role::class)->create(['name' => 'editor']);
    $createPost = factory(Permission::class)->create(['name' => 'create_post']);
    factory(Permission::class)->create(['name' => 'manage_founds']);

    $role->givePermissionTo($createPost);
    $user->assignRole('editor');

    RolePolicies::define();

    $this->actingAs($user);

    $this->assertTrue(Gate::allows('create_post'));
    $this->assertFalse(Gate::allows('manage_founds'));
}
9 likes
jesseschutt's avatar

@Belio Huge thanks for taking the time to post your solution! It helped me out!

1 like

Please or to participate in this conversation.