我怎么能嘲笑我的课的依赖,实现以稳健的方式Iterator
接口?如何模拟一个使用PHPUnit实现Iterator接口的类?
16
A
回答
15
有一对夫妇现有解决方案的这个问题已经上网,但所有我见过的那些共享一个类似的弱点:他们依靠->expects($this->at(n))
。 PHPUnit中的'expect at'函数具有稍微奇怪的行为,因为计数器用于每个方法调用模拟。这意味着如果你有一个直接的foreach之外的方法调用你的迭代器,你必须调整你的迭代器模拟。
的解决方案是创建一个对象保持基本迭代数据(源阵列和位置),并通过该进入returnCallback
闭包。因为它是通过引用传递的,所以对象在调用之间保持最新,所以我们可以模拟每个方法来模拟一个简单的迭代器。现在,我们可以像平常一样使用迭代器模拟,而不必担心严格的呼叫顺序。低于
的抽样方法可以用来设置模拟的迭代器:如果你只需要测试针对通用的迭代,那么PHP(在SPL扩展
/**
* 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;
}
5
- 不能被关闭在PHP> 5.3)已建成在实现Iterable阵列封装:SPL Iterators。例如
$mock_iterator = new \ArrayIterator($items);
$test_class->methodExpectingGenericIterator($mock_iterator);
$resulting_data = $mock_iterator->getArrayCopy();
2
下面是它结合了两者的优点,使用ArrayIterator
内部的解决方案:
/**
* @param array $items
*
* @return \PHPUnit_Framework_MockObject_MockObject|SomeIterator
*/
private function createSomeIteratorMock(array $items = [])
{
$someIterator = $this->createMock(SomeIterator::class)->getMock();
$iterator = new \ArrayIterator($items);
$someIterator
->expects($this->any())
->method('rewind')
->willReturnCallback(function() use ($iterator) {
$iterator->rewind();
})
;
$someIterator
->expects($this->any())
->method('current')
->willReturnCallback(function() use ($iterator) {
return $iterator->current();
})
;
$someIterator
->expects($this->any())
->method('key')
->willReturnCallback(function() use ($iterator) {
return $iterator->key();
})
;
$someIterator
->expects($this->any())
->method('next')
->willReturnCallback(function() use ($iterator) {
$iterator->next();
})
;
$someIterator
->expects($this->any())
->method('valid')
->willReturnCallback(function() use ($iterator) {
return $iterator->valid();
})
;
return $someIterator;
}
相关问题
- 1. 如何模拟一个方法内的接口实现?
- 2. 如何模拟扩展类并实现接口的对象?
- 3. 类设计:类实现接口实现另一个接口
- 4. 行为来模拟一个枚举实现一个接口
- 5. 如何使一个子类实现一个接口?
- 6. 模拟使用PHPUnit
- 7. 模拟类PHPUnit中
- 8. 哪个接口一个类实现?
- 9. 你可以模拟一个实现接口和抽象类的对象吗?
- 10. 如何在另一个接口中实现一个接口
- 11. 使用JMockit模拟自动装配的接口实现
- 12. 实现一个模板接口
- 13. Phpunit:使用模拟替换类
- 14. 如何在java中实现一个接口和多个实现类的junit
- 15. 体验类实现一个接口
- 16. 类实现扩展另一个接口
- 17. 如何实现一个接口来处理类型转换类?
- 18. 如何在Java中使用PowerMockito模拟一个接口
- 19. 如何使用WireMock模拟一个类?
- 20. 人们通常如何模拟在声明中实现接口的类?
- 21. 使用另一个接口从接口实现通用方法
- 22. 如何使用虚拟方法显式实现接口?
- 23. 如何实现定义另一个接口元素的接口
- 24. 如何判断一个类是否是java接口的实现
- 25. 如何在C++中实现非虚拟接口模式?
- 26. 如何识别实现接口的类?
- 27. 如何从接口获得一个枚举到实现该接口的类?
- 28. 你会为2个类实现一个类或2个接口的接口吗
- 29. 实现一个java接口
- 30. 如何使用单例实例模拟一个类
你回答你自己的问题? – epicdev 2013-04-09 16:42:37
我发布了我遇到的问题的解决方案。由于我没有博客,我把它放在这里。我想这是因为有一个复选框,当你张贴问题:) – Dan 2013-04-09 17:33:24
你说得对,@丹做如此使用的一种有效方式。 – Travesty3 2013-07-23 20:31:07