Search code examples
phpunit-testinglaravelstaticmockery

Mockey/Laravel with static call of Authorizer::getResourceOwnerId


I am attempting to use Mockery to fully test some features of a Laravel 5.1 codebase.

I've not done a huge amount of unit testing in Mockery, and certainly not a huge amount with static calls... of which Laravel uses plenty.

I am aware that testing static calls is horrible.. but it can be done. In what I consider good practice (please feel free to correct me), I am attempting to mock these classes to increase separation of tested components.

I am using the \Mockery::mock('alias:{classname}') feature in order to catch these static calls.

For example, to check the current logged in user, the id is found using:

$user_id = (int)Authorizer::getResourceOwnerId();

However, the testing features seem to have some limitations, and I could be using them wrong - the exact question follows below:

Testing structure

My current situation is as follows:

class AuthRoutesTest extends TestCase {

// ...

protected $mock_authorizer;

// ...

public function setUp()
{
    parent::setUp();

    // ...

    $this->mock_authorizer
        ->shouldReceive('getResourceOwnerId')
        ->andReturnValues(
            [null, 3, 3, 3]
        );
}

public function tearDown()
{
    \Mockery::close();
}

Now the tests - all of these require $user_id = (int)Authorizer::getResourceOwnerId(); to return values.

public function testFirst() {
    // $user_id is null, then 3, 3 finally 3
}

And here's the problem:

I want to have.. lets say testSecond() with a separate set of values: say [1,2,null,4].

Each test seems to reset the array (go back to the beginning).

Note: -

  • I have tried to call ->shouldReceive('getResourceOwnerId') again - this does not help
  • I have tried to append the next values to the array, but it starts again at key 0

Is this possible, and if so, how is this done?

(I am aware there are other ways of coding a site.. this is more about testing existing code and avoiding the re-write - at least for now)


Solution

  • If you add byDefault() to your expectation it's possible to override the expectation after it's initiated in the setUp() method.

    You would do something like this:

    public function setUp()
    {
        parent::setUp();
    
        // ...
    
        $this->mock_authorizer
            ->shouldReceive('getResourceOwnerId')
            ->andReturnValues(
                [null, 3, 3, 3]
            )->byDefault();
    }
    

    Then in your second test case it's then possible to override the expectation you defined in the setUp method like this:

    public function testSecond() {
        $this->mock_authorizer
            ->shouldReceive('getResourceOwnerId')
            ->andReturnValues(
                [1,2,null,4]
            );
    }
    

    This post: Override Mockery return values might also be useful.

    You can also read about expectations and the byDefault() method in the Mockery docs.

    Also, I would suggest that you create a facade or use dependency injection for the Authorizer class instead of creating an instance mock, (using Mockery alias) since instance mocks might affect tests in other classes and thereby result in unwanted issues.