Using PHPUnit's returnCallback for a variable length valueMap
2013-10-15Awkward 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');
$this->mockServiceLocator->expects($this->any())
->method('get')
->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;
$this->mockServiceLocator->get('my_service');
...
}
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.