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.
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.
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
- set the class to mock to
- told the mock generator I want to mock the
__constructmethod alone as it will make some checks
- I’m passing no parameters to the class constructor
- I want the mocked class name to be the same as the original class (
ViewController::__constructuses type hinting
- 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.
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.
I found one here and find it immensely useful.