Как я могу заставить PHPUnit MockObjects возвращать разные значения в зависимости от параметра?

У меня есть фиктивный объект PHPUnit, который возвращает 'return value' независимо от его аргументов:

// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
     ->method('methodToMock')
     ->will($this->returnValue('return value'));

Я хочу иметь возможность возвращать другое значение на основе аргументов, переданных фиктивному методу. Я пробовал что-то вроде:

$mock = $this->getMock('myObject', 'methodToMock');

// methodToMock('one')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('one'))
     ->will($this->returnValue('method called with argument "one"'));

// methodToMock('two')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('two'))
     ->will($this->returnValue('method called with argument "two"'));

Но это заставляет PHPUnit жаловаться, если макет не вызывается с аргументом 'two', поэтому я предполагаю, что определение methodToMock('two') перезаписывает определение первого.

Итак, мой вопрос: есть ли способ заставить фиктивный объект PHPUnit возвращать другое значение на основе его аргументов? И если да, то как?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
146
0
84 892
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Вы имеете в виду что-то подобное?

public function TestSomeCondition($condition){
  $mockObj = $this->getMockObject();
  $mockObj->setReturnValue('yourMethod',$condition);
}

Я думаю, что это код SimpleTest, а не PHPUnit. Но нет, это не то, чего я хочу достичь. Скажем, у меня есть фиктивный объект, который возвращает слово для заданного числа. Мой макетный метод должен возвращать «один» при вызове с 1, «два» при вызове с 2 и т. д. $

Ben Dowling 10.11.2008 17:42

У меня была аналогичная проблема, которую я тоже не мог решить (для PHPUnit информации на удивление мало). В моем случае я просто сделал каждый тест отдельным тестом - известный вход и известный выход. Я понял, что мне не нужно делать макет объекта на все руки, мне нужен только конкретный объект для конкретного теста, и поэтому я разделил тесты и могу тестировать отдельные аспекты своего кода как отдельный единица. Я не уверен, применимо ли это к вам или нет, но это зависит от того, что вам нужно проверить.

К сожалению, в моей ситуации это не сработало. Мок передается в метод, который я тестирую, и метод тестирования вызывает фиктивный метод с разными аргументами. Интересно знать, что вы не смогли решить проблему. Похоже, это может быть ограничение PHPUnit.

Ben Dowling 10.11.2008 19:01
Ответ принят как подходящий

Воспользуйтесь обратным вызовом. например (прямо из документации PHPUnit):

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCallbackStub()
    {
        $stub = $this->getMock(
          'SomeClass', array('doSomething')
        );

        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnCallback('callback'));

        // $stub->doSomething() returns callback(...)
    }
}

function callback() {
    $args = func_get_args();
    // ...
}
?>

Выполните любую обработку, которую хотите, в callback () и верните результат на основе ваших $ args, если это необходимо.

Можете дать ссылку на документацию? Я не могу найти его с помощью "Google"

Kris Erickson 10.03.2010 21:43

Обратите внимание, что вы можете использовать метод в качестве обратного вызова, передав массив, например $this->returnCallback(array('MyClassTest','myCallback')).

Patrick Fisher 13.07.2011 00:30

Также должна быть возможность напрямую передать ему закрытие.

Ocramius 24.07.2012 18:25

Это следует использовать только в редких случаях. Я бы предложил вместо этого использовать returnValueMap, поскольку он не требует написания специальной логики в обратном вызове.

Herman J. Radtke III 22.12.2012 08:31

обратный вызов функции имеет то же имя, что и \ PHPUnit_Framework_Assert :: callback

Zdenek Machek 15.04.2014 14:10

Я не могу вас достаточно отблагодарить. Кроме того, с версиями PHP> 5.4 вы можете использовать анонимную функцию в качестве обратного вызова. $this->returnCallback(function() { // ... })

bmorenate 12.11.2015 05:29

Пытаться :

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));

Этот ответ не относится к исходному вопросу, но в нем подробно описывается аналогичная проблема, с которой я столкнулся: убедитесь, что предоставлен определенный набор параметров. PHPUnit with () принимает несколько аргументов, по одному сопоставителю для каждого параметра.

TaZ 25.05.2016 13:44

У меня была аналогичная проблема (хотя и немного другая ... Мне не нужно было другое возвращаемое значение на основе аргументов, но мне пришлось протестировать, чтобы убедиться, что 2 набора аргументов передаются одной и той же функции). Я наткнулся на что-то вроде этого:

$mock = $this->getMock();
$mock->expects($this->at(0))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

$mock->expects($this->at(1))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

Это не идеально, так как требует, чтобы был известен порядок двух вызовов foo (), но на практике это, вероятно, не является плохим тоже.

Вероятно, вы захотите выполнить обратный вызов в стиле ООП:

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnAction()
    {
        $object = $this->getMock('class_name', array('method_to_mock'));
        $object->expects($this->any())
            ->method('method_to_mock')
            ->will($this->returnCallback(array($this, 'returnCallback'));

        $object->returnAction('param1');
        // assert what param1 should return here

        $object->returnAction('param2');
        // assert what param2 should return here
    }

    public function returnCallback()
    {
        $args = func_get_args();

        // process $args[0] here and return the data you want to mock
        return 'The parameter was ' . $args[0];
    }
}
?>

Из последней документации phpUnit: «Иногда заглушенный метод должен возвращать разные значения в зависимости от предопределенного списка аргументов. Вы можете использовать returnValueMap () для создания карты, которая связывает аргументы с соответствующими возвращаемыми значениями».

$mock->expects($this->any())
    ->method('getConfigValue')
    ->will(
        $this->returnValueMap(
            array(
                array('firstparam', 'secondparam', 'retval'),
                array('modes', 'foo', array('Array', 'of', 'modes'))
            )
        )
    );

Ссылка в посте старая, правильная здесь: returnValueMap ()

hejdav 18.09.2015 15:06

Вы также можете вернуть аргумент следующим образом:

$stub = $this->getMock(
  'SomeClass', array('doSomething')
);

$stub->expects($this->any())
     ->method('doSomething')
     ->will($this->returnArgument(0));

Как вы можете видеть в Издевательская документация, метод returnValue($index) позволяет возвращать заданный аргумент.

Я думаю, что Stub vs Mock уже сбивает с толку многих людей. Вы усложняете задачу, выполняя $stub = $this->getMock(.

barell 17.03.2021 12:25

Это не совсем то, о чем вы спрашиваете, но в некоторых случаях это может помочь:

$mock->expects( $this->any() ) )
 ->method( 'methodToMock' )
 ->will( $this->onConsecutiveCalls( 'one', 'two' ) );

onConsecutiveCalls - возвращает список значений в указанном порядке

Передайте двухуровневый массив, где каждый элемент представляет собой массив:

  • сначала параметры метода, а наименьшее - возвращаемое значение.

пример:

->willReturnMap([
    ['firstArg', 'secondArg', 'returnValue']
])
$this->BusinessMock = $this->createMock('AppBundle\Entity\Business');

    public function testBusiness()
    {
        /*
            onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called .
        */
        $this->BusinessMock ->method('getEmployees')
                                ->will($this->onConsecutiveCalls(
                                            $this->returnArgument(0),
                                            $this->returnValue('employee')                                      
                                            )
                                      );
        // first call

        $this->assertInstanceOf( //$this->returnArgument(0),
                'argument',
                $this->BusinessMock->getEmployees()
                );
       // second call


        $this->assertEquals('employee',$this->BusinessMock->getEmployees()) 
      //$this->returnValue('employee'),


    }

Другие вопросы по теме