Как я могу получить 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, чтобы вернуть другое значение на основе его аргументов? И если да, то как?
11 ответов:
использовать обратный вызов. например (прямо из документации 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 по мере необходимости.
из последних документов phpUnit: "иногда метод stubbed должен возвращать разные значения в зависимости от предопределенного списка аргументов. Вы можете использовать returnValueMap() создать карту, которая связывает аргументы с соответствующими значениями вернуться."
$mock->expects($this->any()) ->method('getConfigValue') ->will( $this->returnValueMap( array( array('firstparam', 'secondparam', 'retval'), array('modes', 'foo', array('Array', 'of', 'modes')) ) ) );
У меня была аналогичная проблема (хотя и немного другая... Мне не нужно было другое возвращаемое значение на основе аргументов, но пришлось проверить, чтобы убедиться, что 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(...));
это не идеально, так как требуется, чтобы порядок 2 вызовов 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]; } } ?>
Это не совсем то, что вы просите, но в некоторых случаях это может помочь:
$mock->expects( $this->any() ) ) ->method( 'methodToMock' ) ->will( $this->onConsecutiveCalls( 'one', 'two' ) );
onConsecutiveCalls - возвращает список значений в указанном порядке
передать двухуровневый массив, где каждый элемент является массивом:
- во-первых, это параметры метода, и наименее возвращаемое значение.
пример:
->willReturnMap([ ['firstArg', 'secondArg', 'returnValue'] ])
вы также можете вернуть аргумент следующим образом:
$stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnArgument(0));
Как вы можете видеть в разделе насмешливый документации метод
returnValue($index)
позволяет вернуть данный аргумент.
вы имеете в виду что-то вроде этого?
public function TestSomeCondition($condition){ $mockObj = $this->getMockObject(); $mockObj->setReturnValue('yourMethod',$condition); }
У меня была аналогичная проблема, которую я тоже не мог решить (на удивление мало информации о PHPUnit). В моем случае я просто сделал каждый тест отдельным тестом-известным входом и известным выходом. Я понял, что мне не нужно было делать макет объекта jack-of-all-trades, мне нужен был только конкретный для конкретного теста, и поэтому я отделил тесты и могу тестировать отдельные аспекты моего кода как отдельную единицу. Я не уверен, если это может быть применимо к вам или нет, но это вплоть до того, что вам нужно проверить.
$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'), }