AlbertMulaki's avatar

How can i test that the authorize method has authorized the user to do the request.

How can i test that the authorize method has authorized the user to do the request, and check if this function has been called.

/**
 * Determine if the user is authorized to make this request.
 *
 * @return bool
 */
public function authorize()
{
    $comment = Comment::find($this->route('comment'));

    return $comment && $this->user()->can('update', $comment);
}

By testing i mean write automated tests with phpunit.

0 likes
4 replies
Borisu's avatar
Borisu
Best Answer
Level 37

Well you can sign in a user who can do whatever you authorize and then assert that the action succeeded.

In a test:

$user = factory('App\User')->create(['can' => 'update_comments']);  // or however you do that in your database...
$this->actingAs($user)
    ->post(route('update.comment'), ['comment' => 'blah blah'])
    ->assertRedirect(route('comments'));

Something along these lines should be enough. If you provide some more details we can work it out exactly.

1 like
AlbertMulaki's avatar

@Borisu I have about 7 roles:

$roles = [
    'SuperAdmin',
    'Admin',
    'MediaAdmin',
    'InstitutionAdmin',
    'DataEntryUser',
    'ViewOne',
    'ViewAll'
];

Right now i do something like this:

    public function test_super_admin_can_create_a_patient()
    {
        $this->signInAsSuperAdmin();

        $this->post(action('ChildrensController@store'), $this->childForm);

        $this->performAssertsForThisForm();
    }

    public function test_admin_can_create_a_patient()
    {
        $this->signInAsAdmin();

        $this->post(action('ChildrensController@store'), $this->childForm);

        $this->performAssertsForThisForm();
    }

    public function test_view_one_user_cannot_create_a_patient()
    {
        $this->withExceptionHandling();

        $this->signInAsViewOneUser();

        $this->post(action('ChildrensController@store'), $this->childForm)
            ->assertStatus(403);
    }

   ...

for every role. I wonder if this is the best approach. Also it would be nice if i could just test the policy like this:

   /** @test */
    public function authorized_users_can_create_a_media()
    {
        $mediaPolicy = new MediaPolicy();

        $userTypes = [
            'SuperAdmin',
            'Admin',
            'MediaUser',
            'InstitutionAdmin',
        ];

        foreach($userTypes as $userType){
            $this->assertTrue($mediaPolicy->create(create('App\Entities\User', ['UserType' => $userType])));
        }
    }

And then with some kind of mocking or without mocking, assert that the authorize function has been called, with the can do thing:

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return $this->user()->can('create', Media::class); // this function right here has been called. 
    }

I think that this would be better, but i may be wrong. Do you have any experience about this type of testing?

Borisu's avatar

My personal preference when testing many roles is to still keep them in separate functions. This way you have a very verbose description of the roles and what they can do.

Having said that the method you suggested is also valid. I would just create four users:

$sa = create('App\User', ['UserType' => 'SuperAdmin']);
...
$users = collect($sa, $admin, $mediaUser, $iAdmin);

foreach ($users as $user) {
    $this->assertTrue($user->can('create', Media::class));
}

This way you can just call the can method directly on the user and assert they can do something.

I still think it's best to go from the outside in. Visit a url (or post), assert something happened. This way you make sure your workflow is correct and don't bother with all the small details.

1 like

Please or to participate in this conversation.