我怎麼能嘲笑我的課的依賴,實現以穩健的方式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. 我可以用PHPUnit模擬一個接口實現嗎?
- 2. 在鏈表類中實現Iterator接口
- 3. 如何模擬一個方法內的接口實現?
- 4. 如何模擬擴展類並實現接口的對象?
- 5. 類設計:類實現接口實現另一個接口
- 6. 行爲來模擬一個枚舉實現一個接口
- 7. 如何使一個子類實現一個接口?
- 8. 如何分離實現相同接口的兩個類的函數模擬?
- 9. 模擬使用PHPUnit
- 10. 模擬使用PHPUnit
- 11. 創建一個實現接口的類
- 12. 模擬類PHPUnit中
- 13. 另一個類中使用的PHPUnit模擬方法
- 14. 哪個接口一個類實現?
- 15. 如何實現operator-> for iterator類型?
- 16. 你可以模擬一個實現接口和抽象類的對象嗎?
- 17. 如何實現虛擬網絡接口
- 18. PHPUnit:如何模擬一個類的功能?
- 19. 使用JMockit模擬自動裝配的接口實現
- 20. 如何在另一個接口中實現一個接口
- 21. 如何檢查是否一個類實現一個接口
- 22. 如何讓一個類正確地實現一個接口?
- 23. 實現接口到一個類:接口到接口
- 24. 如何記錄一個實現多個接口的類?
- 25. 實現一個模板接口
- 26. Phpunit:使用模擬替換類
- 27. 如何使用PHPUnit模擬SimpleXMLElement對象?
- 28. 如何使用PHPUnit橋來模擬DNS?
- 29. 如何在java中實現一個接口和多個實現類的junit
- 30. PHPUnit代碼實現接口的抽象類的覆蓋範圍
你回答你自己的問題? – epicdev 2013-04-09 16:42:37
我發佈了我遇到的問題的解決方案。由於我沒有博客,我把它放在這裏。我想這是因爲有一個複選框,當你張貼問題:) – Dan 2013-04-09 17:33:24
你說得對,@丹做如此使用的一種有效方式。 – Travesty3 2013-07-23 20:31:07