Using PHPUnit's returnCallback for a variable length valueMap


Awkward title aside, this is just a quick post about something I rigged together the other day. I have a mocked service locator object that needed to implement returnValueMap, but where the contents of the valueMap would vary based on which test I was executing. PHPUnit does not natively support modifying the valueMap after it's been assigned, so I wanted a way to append items to the map without re-defining the whole mock for every test.

Enter returnCallback

$this->returnCallback allows you to specify just about any function to produce your mock output, including one that's locally defined.

protected $mockServiceLocator;
protected $services = array();

protected function setUp()
    $this->mockServiceLocator = $this->getMock('ServiceLocator');
        ->will($this->returnCallback(array($this, 'serviceResponder')));

    $mockUbiquitousService = $this->getMock('UbiquitousService');
    $this->services['ubiquitous_service'] = $mockUbiquitousService;

 * Fake way of allowing us to append new entries to returnValueMap
 * @param string $serviceName Service name to fetch from locator
 * @return PHPUnit_Framework_MockObject_MockObject
public function serviceResponder($serviceName)
    return $this->services[$serviceName];

public function testServiceLocator()
    $mockService = $this->getMock('Service');
    $this->services['my_service'] = $mockService;

In this way we're able to modify the local services property on the fly (per test) to contain any necessary mocks that we want our mocked Service Locator to provide.