Injecting mocks into type-hinted parameters

I’m very fond of the use of interfaces over class inheritance in code and, while implementing the ViewController class, in all its dependency injectability glory, I’ve got one reason more to do so.

What I’m testing

The ViewController class sports a constructor with fully injectable dependencies that’s meant to be used in factories (me, as a future user, would not like to be left in charge of remembering them all) and uses type hinting to suggest and funnel what it will actually take as a legit argument. The ViewController::__construct() method signature reads like

public function __construct( \TAD\MVC\Helpers\FilePathResolver $FilePathResolver, \TAD\Helpers\Interfaces\GlobalFunctionsAdapter $globalFunctionsAdapter, \TAD\Interfaces\GlobalVariablesAdapter $globalVariablesAdapter, $elementName);

It proved quite hard to test; I made the constructor method accept all of its dependencies up-front first and foremost to be able to test it and not being able to do so proved quite a shock.

Not so fluent man!

Since I will mock all of ViewController dependencies I begin mocking \TAD\MVC\Helpers\FilePathResolver and being it a concrete class that’s easily done in an helper method I’ve created in the test class

$className = 'TAD\MVC\Helpers\FilePathResolver';
$this->filePathResolver = $this->getMock( $className, array( "__construct" ), array(), $className, FALSE );
$this->filePathResolver->rootFilePath = '/folder';

aside for the last line, needed in the tests, I’ve (reading getMock parameters):

  1. set the class to mock to TAD\MVC\Helpers\FilePathResolver
  2. told the mock generator I want to mock the __construct method alone as it will make some checks
  3. I’m passing no parameters to the class constructor
  4. I want the mocked class name to be the same as the original class (TAD\MVC\Helpers\FilePathResolver) since ViewController::__construct uses type hinting
  5. I do not want the original constructor to be called

As a PHPUnit user I should be able to do the same using the fluent interface like

$this->filePathResolver = $this->getMockBuilder( $className )->setMockClassName( $className )->disableOriginalConstructor()->setMethods( array ( '__construct' ));

But that’s not the case. While the first solution will pass the type hinting check the second fluent one will fail, no matter the order of the fluent methods call, with the message

ErrorException: Argument 1 passed to TAD\MVC\Controllers\ViewController::__construct() must be an instance of TAD\MVC\Helpers\FilePathResolver, instance of PHPUnit_Framework_MockObject_MockBuilder given

So the fluent interface seems not to work the same way as the classic (the getMock) one and that’s detailed in a GitHub issue about this very specific problem.

It gets easier with interfaces

Having successfully mocked the FilePathResolver class the next lines in the test helper method will mock the two interface requirements

$className = 'TAD\Interfaces\GlobalFunctionsAdapter';
$this->functions = $this->getMock( $className );
$className = 'TAD\Interfaces\GlobalVariablesAdapter';
$this->globals = $this->getMock( $className );

And this works perfectly. The class naming problem above will not come into play when mocking interfaces since the getMock method will return a mock class, but nonetheless a class, implementing the interface and the type check will pass.

PHPUnit cheat-sheet

I found one here and find it immensely useful.