I've started relying heavily on a mocking framework in php for my unit tests.
My concern is that with a dynamic language, there is no way of enforcing a return type. When mocking, you have to ensure that the return type of your mocked method is correct.
Take for example the following interface
interface MyInterface {
/**
* @return SomeObject
*/
public function myMethod();
}
If we are unit testing a class which requires an instance of MyInterface
, we would mock the myMethod
function to return a known SomeObject
.
My concern is what happens if we accidentally have our mocked method return a different type of object, e.g. SomeOtherObject, and SomeOtherObject and SomeObject are not the same duck type (don't have the same methods). We'll now have code that is relying on having
SomeOtherObject, when all implementations of
MyInterfacemyMethod
will return
SomeObject`.
For example, we could write the following production code;
$someOtherObject = $myInterfaceImp->myMethod();
$newObj = new NewObject($someOtherObject);
Hopefully the issue is obvious. We are passing what we think is SomeOtherObject
into a constructor. Our tests will pass, but its very likely that in production we will get failures as myMethod()
will actually be returning SomeObject
. We then try passing this into the constructor, and get an error if there is a type check, or a non existent method is called.
Unless we write very detailed integration and acceptance tests using the real implementations (basically we'd have to ensure they covered all the testing we do an the unit level) we may not ever realise that we have an issue until we receive some runtime error in production.
Other than developer discipline, is there any way to mitigate the risk of incorrect mocks and implementations?