Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a mock in phpunit without mocking any methods?

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?

like image 244
Brian Kendig Avatar asked Feb 22 '12 15:02

Brian Kendig


People also ask

Which method is used to create a mock with PHPUnit?

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.

Can you mock static methods PHPUnit?

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.

How do you create a mock method?

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().

What is stub in PHPUnit?

Stub. Stubs are used with query like methods - methods that return things, but it's not important if they're actually called.


3 Answers

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.

like image 162
David Harkness Avatar answered Sep 27 '22 16:09

David Harkness


Another hacky, but succinct solution is simply to list the magic constructor as one of the mocked methods:

$mock = $this->getMock('MyClass', array('__construct'));
like image 31
Mike Petrovich Avatar answered Sep 26 '22 16:09

Mike Petrovich


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);
like image 30
urlichsanais Avatar answered Sep 25 '22 16:09

urlichsanais