в 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, но в этом весь смысл делать модульный тест, мне, возможно, придется его рефакторировать, но производство от этого не пострадает)