Как я могу заставить PHPUnit MockObjects возвращать разные значения в зависимости от параметра?
-
07-07-2019 - |
Вопрос
У меня есть макет 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 возвращать другое значение в зависимости от его аргументов?И если да, то как?
Решение
Воспользуйтесь обратным вызовом. например (прямо из документации 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: " Иногда метод с заглушкой должен возвращать разные значения в зависимости от предварительно определенного списка аргументов. Вы можете использовать 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). В моем случае я просто сделал каждый тест отдельным тестом - известный ввод и известный вывод. Я понял, что мне не нужно создавать фиктивный объект «мастер на все руки», мне нужен был только конкретный объект для конкретного теста, и, таким образом, я разделил тесты и могу тестировать отдельные аспекты моего кода как отдельный Блок. Я не уверен, может ли это быть применимо к вам или нет, но это зависит от того, что вам нужно проверить.
$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'),
}
Попробуйте:
->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));