When I'm unit-testing my php code with PHPUnit, I'm trying to figure out the right way to mock an object without mocking any of its methods.
The problem is that if I don't call getMockBuilder()->setMethods()
, then all methods on the object will be mocked and I can't call the method I want to test; but if I do call setMethods()
, then I need to tell it what method to mock but I don't want to mock any methods at all. But I need to create the mock so I can avoid calling the constructor in my test.
Here's a trivial example of a method I'd want to test:
class Foobar
{
public function __construct()
{
// stuff happens here ...
}
public function myMethod($s)
{
// I want to test this
return (strlen($s) > 3);
}
}
I might test myMethod()
with:
$obj = new Foobar();
$this->assertTrue($obj->myMethod('abcd'));
But this would call Foobar's constructor, which I don't want. So instead I'd try:
$obj = $this->getMockBuilder('Foobar')->disableOriginalConstructor()->getMock();
$this->assertTrue($obj->myMethod('abcd'));
But calling getMockBuilder()
without using setMethods()
will result in all of its methods being mocked and returning null, so my call to myMethod()
will return null without touching the code I intend to test.
My workaround so far has been this:
$obj = $this->getMockBuilder('Foobar')->setMethods(array('none'))
->disableOriginalConstructor()->getMock();
$this->assertTrue($obj->myMethod('abcd'));
This will mock a method named 'none', which doesn't exist, but PHPUnit doesn't care. It will leave myMethod() unmocked so that I can call it, and it will also let me disable the constructor so that I don't call it. Perfect! Except that it seems like cheating to have to specify a method name that doesn't exist - 'none', or 'blargh', or 'xyzzy'.
What would be the right way to go about doing this?
PHPUnit provides methods that are used to automatically create objects that will replace the original object in our test. createMock($type) and getMockBuilder($type) methods are used to create mock object. The createMock method immediately returns a mock object of the specified type.
Stubbing and mocking internal static methods As Sebastian Bergmann explains in one of his blogposts, since PHPUnit 3.5 it's possible to stub & mock static methods.
Let's test the MathApplication class, by injecting in it a mock of calculatorService. Mock will be created by Mockito. Here we've added two mock method calls, add() and subtract(), to the mock object via when(). However during testing, we've called subtract() before calling add().
Stub. Stubs are used with query like methods - methods that return things, but it's not important if they're actually called.
You can pass null
to setMethods()
to avoid mocking any methods. Passing an empty array will mock all methods. The latter is the default value for the methods as you've found.
That being said, I would say the need to do this might point out a flaw in the design of this class. Should this method be made static or moved to another class? If the method doesn't require a completely-constructed instance, it's a sign to me that it might be a utility method that could be made static.
Another hacky, but succinct solution is simply to list the magic constructor as one of the mocked methods:
$mock = $this->getMock('MyClass', array('__construct'));
In case, any method, e.g. that is called through the entityManager, can be used you might be able to use this:
$this->entityManager
->expects($this->any())
->method($this->anything())
->willReturn($repository);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With