mtmacdonald
mtmacdonald

Reputation: 15070

How to test a class which depends on an Eloquent model with relationships?

What is the best way to write a unit test for a class which depends on an Eloquent model with relationships? E.g.

context: I'm using Laravel with Authority RBAC for access control. I want to find the best way to test my access rules in a unit test. Which means I need to pass the user dependencies to Authority during the test.

Upvotes: 2

Views: 1655

Answers (1)

awei
awei

Reputation: 1164

If you're writing unit tests, you shouldn't ever use a database. Testing against a database would be considered an integration test. Check out Roy Osherove's videos.

To answer your question, (and not having delved into Authority RBAC, I'd do something like this:

// assuming some RBAC class
SomeRBACClass extends RBACBaseClass {

     function validate(UserClass $user) {
         if (!$roles = $user->getRoles())
         {
             return false;
         }

         $allowed = array('admin', 'superadmin');

         foreach ($roles as $role) {
             if (in_array($role->name, $allowed)) {
                 return true;
             }
         }

         return false;
     }

}

SomeRBACClassTest extends TestCase {

    function test_validate_WhenPassedUser_callsGetRolesOnUserWithNoArgs()
    {
        $rbac = new SomeRBACClass();
        $user = Mockery::mock('UserClass');

        $user->shouldReceive('getRoles')->once()->withNoArgs();

        $rbac->validate($user);
    }

    function test_validate_getRolesOnUserReturnsCollectionOfRoles_CallsGetAttributeWithNameOnFirstRole() {
        $rbac = new SomeRBACClass();
        $user = Mockery::mock('UserClass');
         // assuming $user->getRoles() returns a collection
        $collection = new \Illuminate\Support\Collection(array(
             $role1 = Mockery::mock('Role'),
             $role2 = Mockery::mock('Role'),
        ));
        $user->shouldReceive('getRoles')->andReturn($collection);

        $role1->shouldReceive('getAttribute')->once()->with('name');

        $rbac->validate($user);
    }

    function test_validate_getAttributeWithNameOnRoleReturnsValidRole_ReturnsTrue() {
        $rbac = new SomeRBACClass();
        $user = Mockery::mock('UserClass');
         // assuming $user->getRoles() returns a collection
        $collection = new \Illuminate\Support\Collection(array(
             $role1 = Mockery::mock('Role'),
             $role2 = Mockery::mock('Role'),
        ));
        $user->shouldReceive('getRoles')->andReturn($collection);
        $role1->shouldReceive('getAttribute')->andReturn('admin');

        $result = $rbac->validate($user);

        $this->assertTrue($result);
    }

This is not a thorough example of all the unit tests that I would write, but it's a start. E.g., I would also validate that when no roles are returned, that the result is false.

Upvotes: 0

Related Questions