PHPUnit的returnValueMap没有产生预期的结果

Bra*_*och 38 php phpunit cakephp

我正在尝试使用PHPUnit的returnValueMap()来删除读取的结果.它没有产生预期的结果,但是等效的returnCallback()确实如此.如果您想亲自检查,我已经提供了我的测试用例.

returnValueMap()

$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');
Run Code Online (Sandbox Code Playgroud)

结果:

Subscription ID: NULL
Name: NULL
Run Code Online (Sandbox Code Playgroud)

returnCallback()

$enterprise = $this->getMock('Enterprise', array('field'));
$enterprise->expects($this->any())
    ->method('field')
    ->will($this->returnCallback(function ($arg) {
        $map = array(
            'subscription_id' => null,
            'name' => 'Monday Farms'
        );
        return $map[$arg];
    }));
$enterprise->subscribe('basic');
Run Code Online (Sandbox Code Playgroud)

结果:

Subscription ID: NULL
Name: string(12) "Monday Farms"
Run Code Online (Sandbox Code Playgroud)

企业::订阅

public function subscribe() {
    echo 'Subscription ID: ';
    var_dump($this->field('subscription_id'));
    echo 'Name: ';
    var_dump($this->field('name'));
}
Run Code Online (Sandbox Code Playgroud)

为什么returnValueMap()不像我期望的那样工作?我到底错过了什么?

小智 100

我遇到了同样的问题,最终发现returnValueMap()必须映射函数的所有参数,包括可选参数,然后是所需的返回值.

Zend Framework的示例函数:

public function getParam($key, $default = null)
{
    $key = (string) $key;
    if (isset($this->_params[$key])) {
        return $this->_params[$key];
    }

    return $default;
}
Run Code Online (Sandbox Code Playgroud)

必须像这样映射:

$request->expects($this->any())
        ->method('getParam')
        ->will($this->returnValueMap(array(array($param, null, $value))));
Run Code Online (Sandbox Code Playgroud)

如果没有中间的null,它将无法工作.

  • 你刚救了我**很多头疼的事.谢谢.PS:有点遗憾的是PHPUnit的许多怪癖都没有在其官方文档中.... (9认同)

use*_*602 8

我一直在寻找同样的问题,最终出于绝望xdebug - 逐步通过Framework/MockObject/Stub/ReturnValueMap.php和Framework/MockObject/InvocationMocker.php [在方法InvocationMocker :: invoke(PHPUnit_Framework_MockObject_Invocation $ invocation)]中,我观察到以下几点:

  1. 在调用存根函数时,您提供的map-array中的值不仅必须与预期参数相同,而且它们必须具有相同的类型.这是因为在ReturnValueMap :: invoke()方法中的Framework/MockObject/Stub/ReturnValueMap.php中,提供的参数与预期参数之间的比较在第75行中进行了比较,如下所示:

    if ($invocation->parameters === $map) {
    
    Run Code Online (Sandbox Code Playgroud)

    所以,预期的结果

    $mock->myStubbedMethod( "1", "2" )
    
    Run Code Online (Sandbox Code Playgroud)

    使用地图数组

    array(
        array( 1, 1, 500 ),
        array( 1, 2, 700 )
    )
    
    Run Code Online (Sandbox Code Playgroud)

    会失望的.相反,结果将为NULL.

  2. 在一个更微妙的点上,你可能已经使用两种不同的模拟方案来破坏方法(就像我做的那样 - 是的,傻我!)

    因此,为了阐明,第一个模拟存根可以包含

    $mock->expects( $this->any() )
           ->method('myStubbedMethod')
           ->will( $this->returnValue(750) );
    
    Run Code Online (Sandbox Code Playgroud)

    然后,在相同的单元测试方法中,它可以包含

    $arrMap = array(
        array( 1, 1, 500 ),
        array( 1, 2, 700 ),
        array( 2, 3, 1500 ),
    );
    $mock->expects( $this->any() )
            ->method('myStubbedMethod')
            ->will( $this->returnValueMap($arrMap) );
    
    Run Code Online (Sandbox Code Playgroud)

    调用stubbed方法时,将实现map-array版本.这是显而易见的,不言而喻的,但是当你在当下的热度下进行编码,并且在你开发的过程中将不同的代码行为分开时,它很容易被忽视.