Ben Dowling Ben Dowling - 4 months ago 32
PHP Question

How can I get PHPUnit MockObjects to return different values based on a parameter?

I've got a PHPUnit mock object that returns

'return value'
no matter what its arguments:

// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
->method('methodToMock')
->will($this->returnValue('return value'));


What I want to be able to do is return a different value based on the arguments passed to the mock method. I've tried something like:

$mock = $this->getMock('myObject', 'methodToMock');

// methodToMock('one')
$mock->expects($this->any))
->method('methodToMock')
->with($this->equalTo('one'))
->will($this->returnValue('method called with argument "one"'));

// methodToMock('two')
$mock->expects($this->any))
->method('methodToMock')
->with($this->equalTo('two'))
->will($this->returnValue('method called with argument "two"'));


But this causes PHPUnit to complain if the mock isn't called with the argument
'two'
, so I assume that the definition of
methodToMock('two')
overwrites the definition of the first.

So my question is: Is there any way to get a PHPUnit mock object to return a different value based on its arguments? And if so, how?

Answer

Use a callback. e.g. (straight from PHPUnit documentation):

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCallbackStub()
    {
        $stub = $this->getMock(
          'SomeClass', array('doSomething')
        );

        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnCallback('callback'));

        // $stub->doSomething() returns callback(...)
    }
}

function callback() {
    $args = func_get_args();
    // ...
}
?>

Do whatever processing you want in the callback() and return the result based on your $args as appropriate.