til

Today I Learned

View the Project on GitHub

alias mocking

The Mockery library and dependency injection allow you to mock external dependencies such as databases and filesystems. This is great, but doesn’t work if that dependency is being called statically within the code you want to test.

Imagine this scenario:

class Foo {
    public function __construct(Database $db = null) {

        // ...

        Database::someDatabaseStuff(...);
    }
}

and

function testFoo() {
    $foo = new Foo(Mockery::mock(Database::class));
    // ...
}

Even though you did the right thing and mocked the Database class, any Foo tests will fail if there is no database available (and there shouldn’t be in unit tests) because of the explicit static call in the constructor.

Alias mocking to the rescue.

function testFoo() {
    $db = Mockery::mock('alias:Database');
    $db->shouldReceive('someDatabaseStuff');

    $foo = new Foo($db);
    // ...
}

This will route all calls to Database through the mock. This will work as is if run standalone, but if you want to run it alongside other tests you have to add these annotations to each test:

@runInSeparateProcess
@preserveGlobalState disabled

More details here: https://blog.gougousis.net/mocking-static-methods-with-mockery/

The Mockery documentation does not recommend using aliasing, but it was a neat solution to the problem I had.