ReturnValueMap PHPUnit не дает ожидаемых результатов

Я пытаюсь использовать 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');

результаты:

Subscription ID: NULL
Name: NULL

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');

результаты:

Subscription ID: NULL
Name: string(12) "Monday Farms"

Enterprise:: подписаться

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

почему returnValueMap () не работает так, как я ожидаю? Что именно я упускаю?

3 ответов


у меня была такая же проблема, и в конце концов я узнал, что returnValueMap () должен отображать все параметры вашей функции, включая необязательные, затем желаемое возвращаемое значение.

пример функции из Zend Framework:

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

    return $default;
}

должен отображаться следующим образом:

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

без null в середине он не будет работать.


я охотился за этой же проблемой и в конечном итоге из отчаяния xdebug-шагнул через Framework/MockObject/Stub/ReturnValueMap.php и Framework/MockObject / InvocationMocker.php [в методе InvocationMocker:: invoke (PHPUnit_Framework_MockObject_Invocation $invocation)], и я заметил следующие моменты:

  1. не только значения в массиве карт, который вы предоставляете, должны совпадать с ожидаемыми параметрами, когда функция stubbed звонили, но они должны быть одного типа. Это связано с тем, что внутри Framework/MockObject/Stub / ReturnValueMap.php в методе ReturnValueMap:: invoke () сравнение между предоставленными параметрами и ожидаемыми параметрами сравнивается в строке 75 следующим образом:

    if ($invocation->parameters === $map) {
    

    Итак, ожидаемый результат

    $mock->myStubbedMethod( "1", "2" )
    

    использование map-массива

    array(
        array( 1, 1, 500 ),
        array( 1, 2, 700 )
    )
    

    разочарует. Вместо этого результатом будет значение NULL.

  2. на гораздо более тонкий момент, Вы, возможно, заглушили метод, используя два разных макетных сценария (как и я - да, глупый я!)

    Итак, чтобы прояснить, первый макет-заглушка может содержать

    $mock->expects( $this->any() )
           ->method('myStubbedMethod')
           ->will( $this->returnValue(750) );
    

    а затем позже, в том же методе модульного тестирования, он может содержать

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

    при вызове метода stubbed-будет реализована версия массива карт. Это очевидно и самоочевидно, однако при кодировании в пылу момента и при разделении другого кода поведение в вашем уме, когда вы развиваетесь, легко упускается из виду.


проблема, похоже, лежит где-то еще в коде или может быть проблемой со старой версией PHPUnit.

для меня он работает с помощью этого кода:

кошка 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'));
    }

}

выход:

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)

поэтому, хотя я не могу сказать, почему это не работает, я могу, по крайней мере, сказать вам, что вы делаете это правильно и что вы поняли returnValueMap правильно :)