в phpunit есть ли метод, подобный onconsecutivecalls для использования внутри метода "with"?
используя PHPUnit, я издеваюсь над pdo, но я пытаюсь найти способ подготовить более одного оператора запроса базы данных.
$pdo = $this->getPdoMock();
$stmt = $this->getPdoStatementMock($pdo);
$pdo->expects($this->any())
->method('prepare')
->with($this->equalTo($title_query))
->will($this->returnValue($stmt));
$title_stmt = $pdo->prepare($title_query);
$desc_stmt = $pdo->prepare($desc_query);
Я хочу передать что-то похожее на onConsecutiveCalls для метода "with", поэтому я могу подготовить несколько операторов, как показано выше. Как бы ты это сделал?
6 ответов
вы можете сопоставить последовательные вызовы одного и того же метода, написав отдельные ожидания с $this->at()
вместо $this->any()
:
$pdo->expects($this->at(0))
->method('prepare')
->with($this->equalTo($title_query))
->will($this->returnValue($stmt));
$pdo->expects($this->at(1))
->method('prepare')
->with($this->equalTo($desc_query))
->will($this->returnValue($stmt));
$title_stmt = $pdo->prepare($title_query);
$desc_stmt = $pdo->prepare($desc_query);
PHPUnit 4.1 получил новый метод withConsecutive()
. От Тест Двойная Глава:
class FooTest extends PHPUnit_Framework_TestCase
{
public function testFunctionCalledTwoTimesWithSpecificArguments()
{
$mock = $this->getMock('stdClass', array('set'));
$mock->expects($this->exactly(2))
->method('set')
->withConsecutive(
array($this->equalTo('foo'), $this->greaterThan(0)),
array($this->equalTo('bar'), $this->greaterThan(0))
);
$mock->set('foo', 21);
$mock->set('bar', 48);
}
}
каждый аргумент withConsecutive()
для одного вызова указанного метода.
С более поздними версиями PHPUnit принятый ответ может быть упрощен совсем немного.
плюс, хотя это не сразу относится к исходному вопросу, вы можете легко предоставить разные возвращаемые значения для каждого вызова метода через willReturnOnConsecutiveCalls
метод.
$pdo->expects($this->exactly(2))
->method('prepare')
->withConsecutive(
$this->equalTo($title_query),
$this->equalTo($desc_query)
)
->willReturnOnConsecutiveCalls(
$stmt, // returned on the 1st call to prepare()
$stmt // returned on the 2nd call to prepare()
);
единственное, что я нашел похожим на то, что вы спрашиваете, это использование "at":
$mock->expects($this->at(0))->method // etc
$mock->expects($this->at(1))->method // etc
таким образом, вы устанавливаете ожидания в первый раз, когда он называется (в 0), во второй раз и так далее.
несколько человек отметили, что at($index) может использоваться для определенных экземпляров вызовов метода. Дэвид Х. и Вика уточнили, что $index подсчитывает все вызовы ко всем издевательским методам объекта.
кроме того, возможно, стоит отметить, что Тест Удваивает Главу в документации PHPUnit есть предупреждение об этом. Он указывает, что использование at() следует делать с осторожностью, так как это может привести к хрупким тестам, которые слишком сильно зависят от конкретного реализация.
Я использую dataProvider и мне нужно переменное количество выполненных запросов, которые я могу использовать для заполнения моего провайдера, я хочу предоставить массив запросов, которые должны быть выполнены.
Проблема с withConsecutive
заключается в том, что он принимает переменное количество массивов, каждый массив аргументов.
Я решил его с помощью кода follwing, это чувствует себя "взломанным", но работает:
$withConsecutiveArgs = [
[$this->equalTo($title_query)],
[$this->equalTo($desc_query)],
...,
N queries
];
$withConsecutiveReturns = [
$title_stmt,
$desc_stmt,
...,
N returns
];
$methodMock = $pdo->expects($this->exactly(count($args))->method('prepare');
$methodMock->getMatcher()->parametersMatcher = new \PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters($withConsecutiveArgs);
$methodMock->will(new \PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($withConsecutiveReturns));
$title_stmt = $pdo->prepare($title_query);
$desc_stmt = $pdo->prepare($desc_query);
...
$N_s_stmt = $pdo->prepare($N_s_query);
Я надеюсь, что он правильно развивается с будущими версиями PhpUnit (который не уверен, так как я полагаюсь на внутренних lib, но в этом весь смысл делать модульный тест, мне, возможно, придется его рефакторировать, но производство от этого не пострадает)