I\'m trying to use PHPUnit\'s returnValueMap() to stub out the results of a read. It isn\'t yielding the expected results, but an equivalent returnCallback() does. I\'ve made
I've been hunting down this same problem and eventually out of desperation xdebug-stepped through Framework/MockObject/Stub/ReturnValueMap.php and Framework/MockObject/InvocationMocker.php [in method InvocationMocker::invoke(PHPUnit_Framework_MockObject_Invocation $invocation) ], and I've observed the following points:
Not only must the values in the map-array that you supply be the same as the expected parameters when the stubbed function is called, but they MUST BE OF THE SAME TYPE. This is because inside Framework/MockObject/Stub/ReturnValueMap.php in the ReturnValueMap::invoke() method, the comparison between the supplied parameters and the expected parameters is compared in line 75 as follows:
if ($invocation->parameters === $map) {
So, the anticipated result of
$mock->myStubbedMethod( "1", "2" )
using a map-array of
array(
array( 1, 1, 500 ),
array( 1, 2, 700 )
)
will disappoint. Instead, the result will be a NULL.
On a much more subtle point, you may have stubbed the method using two different mock scenarios (as I did - yes, silly me!)
So, to elucidate, the first mock-stub could contain
$mock->expects( $this->any() )
->method('myStubbedMethod')
->will( $this->returnValue(750) );
and then later, in the same unit-test method, it could contain
$arrMap = array(
array( 1, 1, 500 ),
array( 1, 2, 700 ),
array( 2, 3, 1500 ),
);
$mock->expects( $this->any() )
->method('myStubbedMethod')
->will( $this->returnValueMap($arrMap) );
When the stubbed-method is invoked, the map-array version will be implemented. This is obvious and self-evident, however while coding in the heat of the moment, and while separating different code behaviour in your mind as you develop, it's easily overlooked.
I had the same problem and eventually found out that returnValueMap() has to map all parameters of your function, including optional ones, then the desired return value.
Example function from Zend Framework:
public function getParam($key, $default = null)
{
$key = (string) $key;
if (isset($this->_params[$key])) {
return $this->_params[$key];
}
return $default;
}
Has to mapped like this:
$request->expects($this->any())
->method('getParam')
->will($this->returnValueMap(array(array($param, null, $value))));
Without the null in the middle, it won't work.
The Problem seems to lie either somewhere else in the code or might be an issue with an old PHPUnit version.
For me it works using this code:
cat EnterpriseTest.php
<?php
class EnterpriseTest extends PHPUnit_Framework_TestCase {
public function testReturnValueMap() {
$enterprise = $this->getMock('Enterprise', array('field'));
$enterprise->expects($this->any())
->method('field')
->will($this->returnValueMap(array(
array('subscription_id', null),
array('name', 'Monday Farms')
)))
;
$enterprise->subscribe('basic');
}
}
class Enterprise {
public function field($name) {
}
public function subscribe() {
echo 'Subscription ID: ';
var_dump($this->field('subscription_id'));
echo 'Name: ';
var_dump($this->field('name'));
}
}
Output:
phpunit-dev EnterpriseTest.php
PHPUnit 3.7.6 by Sebastian Bergmann.
.Subscription ID: NULL
Name: string(12) "Monday Farms"
Time: 0 seconds, Memory: 6.75Mb
OK (1 test, 1 assertion)
So while I can't tell why it doesn't work I can at least tell you that you are doing it right and that you've understood returnValueMap
correctly :)