PHPUnit - 模拟PDO语句提取

时间:2011-03-21 14:25:15

标签: mocking pdo phpunit fetch

仍然在测试mapper类的过程中,我需要模拟PDO。 但现在我遇到了无限循环问题:

$arrResult = array(
                    array('id'=>10, 'name'=>'abc'),
                    array('id'=>11, 'name'=>'def'),
                    array('id'=>12, 'name'=>'ghi')
                    );

$STMTstub->expects($this->any())
            ->method('fetch')
            ->will($this->returnValue($arrResult));
$PDOstub = $this->getMock('mockPDO');
    $PDOstub->expects($this->any())
            ->method('prepare')
            ->will($this->returnValue($STMTstub));

当然,当测试1 fetch或fetchAll时,该代码是完美的。但是当它进行多次获取时,会发生无限循环。就像那种情况一样:

while($arr = $stmt->fetch()){
    //...
}

所以我希望fetch()循环遍历所有$ arrResult并逐个返回子数组来模拟真正的fetch()行为。我可以“勾选一个功能”这样做吗?

1 个答案:

答案 0 :(得分:4)

您有两种选择:

  1. 对于一些结果,您可以使用at()订购返回的值,或
  2. 为了获得更多结果,您可以使用returnCallback()调用一个能够在多个调用中产生所需结果的函数。
  3. 使用at()非常简单。传入一个PHPUnit匹配的索引,以便选择要触发的期望。请注意,传递给at()的索引遍及对mock的所有调用。如果$STMTstubfetch()的调用之间收到其他模拟调用,则需要相应地调整索引。

    $STMTstub->expects($this->at(0))
              ->method('fetch')
              ->will($this->returnValue($arrResult[0]));
    $STMTstub->expects($this->at(1))
              ->method('fetch')
              ->will($this->returnValue($arrResult[1]));
    $STMTstub->expects($this->at(2))
              ->method('fetch')
              ->will($this->returnValue($arrResult[2]));
    

    使用returnCallback()将需要更多的脚手架,但它避免了所有的索引诡计。 ;)

    public static function yieldResults($name, $results) {
        static $indexes = array();
        if (isset($indexes[$name])) {
            $index = $indexes[$name] + 1;
        }
        else {
            $index = 0;
        }
        self::assertLessThan(count($results), $index);
        $indexes[$name] = $index;
        return $results[$index];
    }
    
    public function testMyPdo() {
        $STMTmock = ...
        $STMTmock->expects($this->any())->method('fetch')
                 ->will($this->returnCallback(function() {
                     return self::yieldResults('testMyPdo', 
                         array(
                             array('id'=>10, 'name'=>'abc'),
                             array('id'=>11, 'name'=>'def'),
                             array('id'=>12, 'name'=>'ghi'),
                         );});
    }
    

    yieldResults()是通用的,只要您为每个结果集提供唯一的$name,它就可以使用任意数量的同步结果集。如果您没有使用PHP 5.3进行回调,请将调用包含在yieldResults()内的另一个函数中,该函数的名称将传递给returnCallback()。我还没有测试过,但看起来还不错。