在phpunit中,是否有类似onconsecutivecalls的方法在“with”方法中使用?

时间:2011-03-16 16:04:58

标签: php unit-testing junit pdo phpunit

使用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 个答案:

答案 0 :(得分:22)

您可以通过使用$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);

答案 1 :(得分:15)

PHPUnit 4.1获得了一个新方法withConsecutive()。来自Test Double Chapter

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()的每个参数都是对指定方法的一次调用。

答案 2 :(得分:10)

使用更新版本的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()
    );

答案 3 :(得分:3)

我发现的唯一一个与你问的相似的是使用'at':

$mock->expects($this->at(0))->method // etc
$mock->expects($this->at(1))->method // etc

因此,您可以在第一次调用(0)时设置预期,第二次调整等等。

答案 4 :(得分:0)

有几个人注意到,($ index)可用于调用方法的特定实例。 David H.和Vika澄清说$ index对所有模拟对象的方法进行ALL调用。

此外,值得注意的是PHPunit文档的Test Doubles Chapter有关于此的警告说明。它指出使用at()应该谨慎,因为它可能导致脆弱的测试,这些测试过于依赖于具体的实现。

答案 5 :(得分:0)

我使用dataProvider并且需要可变数量的已执行查询,我可以使用它来填充我的提供程序,我想提供一个应该执行的查询数组。 withConsecutive的问题在于它需要可变数量的数组,每个数组都是一个参数数组。

我使用以下代码解决了这个问题,感觉" hacky"但是有效:

$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的内部,但这是进行单元测试的全部要点,我可能需要重构它,但生产将会不受此影响)