仍然在测试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()行为。我可以“勾选一个功能”这样做吗?
答案 0 :(得分:4)
您有两种选择:
at()
订购返回的值,或returnCallback()
调用一个能够在多个调用中产生所需结果的函数。使用at()
非常简单。传入一个PHPUnit匹配的索引,以便选择要触发的期望。请注意,传递给at()
的索引遍及对mock的所有调用。如果$STMTstub
在fetch()
的调用之间收到其他模拟调用,则需要相应地调整索引。
$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()
。我还没有测试过,但看起来还不错。