php - 如何模拟使用 PHPUnit 实现 Iterator 接口(interface)的类?

标签 php iterator mocking phpunit

我如何模拟实现 Iterator 的类的依赖项?接口(interface)是否稳健?

最佳答案

网上已经有一些解决这个问题的现有解决方案,但我看到的所有解决方案都有一个类似的弱点:它们依赖于 ->expects($this->at(n))。 PHPUnit 中的 'expects at' 函数有一些奇怪的行为,因为计数器是针对模拟的每个方法调用的。这意味着,如果您在直接 foreach 之外对迭代器进行方法调用,则必须调整迭代器模拟。

解决方案是创建一个包含基本迭代器数据(源数组和位置)的对象,并将其传递给 returnCallback 闭包。因为它是通过引用传递的,所以对象在调用之间保持最新,所以我们可以模拟每个方法来模拟一个简单的迭代器。现在我们可以正常使用迭代器模拟,而不必担心严格的调用顺序。

可用于设置迭代器模拟的示例方法:

/**
 * Setup methods required to mock an iterator
 *
 * @param PHPUnit_Framework_MockObject_MockObject $iteratorMock The mock to attach the iterator methods to
 * @param array $items The mock data we're going to use with the iterator
 * @return PHPUnit_Framework_MockObject_MockObject The iterator mock
 */
public function mockIterator(PHPUnit_Framework_MockObject_MockObject $iteratorMock, array $items)
{
    $iteratorData = new \stdClass();
    $iteratorData->array = $items;
    $iteratorData->position = 0;

    $iteratorMock->expects($this->any())
                 ->method('rewind')
                 ->will(
                     $this->returnCallback(
                         function() use ($iteratorData) {
                             $iteratorData->position = 0;
                         }
                     )
                 );

    $iteratorMock->expects($this->any())
                 ->method('current')
                 ->will(
                     $this->returnCallback(
                         function() use ($iteratorData) {
                             return $iteratorData->array[$iteratorData->position];
                         }
                     )
                 );

    $iteratorMock->expects($this->any())
                 ->method('key')
                 ->will(
                     $this->returnCallback(
                         function() use ($iteratorData) {
                             return $iteratorData->position;
                         }
                     )
                 );

    $iteratorMock->expects($this->any())
                 ->method('next')
                 ->will(
                     $this->returnCallback(
                         function() use ($iteratorData) {
                             $iteratorData->position++;
                         }
                     )
                 );

    $iteratorMock->expects($this->any())
                 ->method('valid')
                 ->will(
                     $this->returnCallback(
                         function() use ($iteratorData) {
                             return isset($iteratorData->array[$iteratorData->position]);
                         }
                     )
                 );

    $iteratorMock->expects($this->any())
                 ->method('count')
                 ->will(
                     $this->returnCallback(
                         function() use ($iteratorData) {
                             return sizeof($iteratorData->array);
                         }
                     )
                 );

    return $iteratorMock;
}

关于php - 如何模拟使用 PHPUnit 实现 Iterator 接口(interface)的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15907249/

相关文章:

c++ - 通过常量迭代器从 STL 容器中删除

c++ - 如何在 map 中使用 const?

javascript - 声明一个 JavaScript 变量来存放 php 变量

php - 现场事件的自动 PayPal 付款

php - 如何通过文本验证将值从 html 页面发送到 php 页面

PHP REGEX preg_match_all 特定行之后的每一行

java - 如何访问源自数据库的 ArrayList 内的 HashMap ?

php - vfsstream 路径和真实路径

spring - 为 Spring JUnit 选择 Mocking 框架

java - Tomcat 和 JDBC 驱动程序