Подтвердить что ты не робот

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

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

Предприятие:: подписаться

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

Почему не возвращает функциюValueMap(), как я ожидаю? Что именно мне не хватает?

4b9b3361

Ответ 1

У меня была такая же проблема, и в итоге выяснилось, что 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))));

Без нуля в середине, это не сработает.

Ответ 2

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

  • Значения в массиве map, которые вы поставляете, должны не совпадать с ожидаемыми параметрами при вызове функции stubbed, но они ДОЛЖНЫ БЫТЬ ОДНОГО ТИПА. Это связано с тем, что внутри Framework/MockObject/Stub/ReturnValueMap.php в методе ReturnValueMap:: invoke() сравнение между параметрами и ожидаемыми параметрами сравнивается в строке 75 следующим образом:

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

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

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

    с использованием массива карт

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

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

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

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

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

    а затем, в том же методе unit-test, он может содержать

    $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-method, будет реализована версия map-array. Это очевидно и само собой разумеется, однако, при кодировании в разгар момента и при раздельном разном кодовом поведении в вашем сознании, когда вы развиваетесь, его легко упускают из виду.

Ответ 3

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

Для меня это работает с использованием этого кода:

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

}

Вывод:

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:)