PHPUnit - 模拟 PDO 语句获取

发布于 2024-10-24 06:17:51 字数 823 浏览 7 评论 0原文

仍在测试映射器类的过程中,我需要模拟 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() 行为。我可以“挂钩一个函数”来这样做吗?

Still in the process of testing a mapper class, I need to mock PDO.
But now I ran into an infinite loop problem:

$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));

Of course, that code is perfect when it come to test 1 fetch or a fetchAll. But when it come to multiple fetch, the infinite loop happen. Like in that case:

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

So I'd like the fetch() to loop through all the $arrResult and return the sub-array one by one to simulate the true fetch() behavior. Can I "hook a function" to do so or something ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只是在用心讲痛 2024-10-31 06:17:51

您有两种选择:

  1. 对于一些结果,您可以使用 at() 对返回值进行排序,或者
  2. 对于更多结果,您可以使用 returnCallback() 调用一个函数通过多次调用产生所需的结果。

使用 at() 非常简单。您传入 PHPUnit 与调用相匹配的索引,以选择要触发的期望。请注意,传递给 at() 的索引涵盖对模拟的所有调用。如果 $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()。我还没有测试过,但看起来相当不错。

You have two options:

  1. For a few results you can use at() to order the returned values, or
  2. for more results you can use returnCallback() to call a function that yields the desired results across multiple calls.

Using at() is pretty straight-forward. You pass in an index that PHPUnit matches up against the calls to pick which expectation to fire. Note that the index passed to at() is across all calls to the mock. If $STMTstub will receive other mocked calls between the calls to fetch(), you'll need to adjust the indexes accordingly.

$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]));

Using returnCallback() will require a bit more scaffolding, but it avoids all the index shenanigans. ;)

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() is generic and will work with any number of simultaneous result sets as long as you give each a unique $name. If you're not using PHP 5.3 with callbacks, wrap the call to yieldResults() inside another function whose name you pass to returnCallback(). I haven't tested it out, but it seems fairly sound.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文