幾年前,我開始學習Zend Framework之後的this tutorial。在那裏,它顯示了使用Zend\Db\Adapter\Adapter
類創建映射器來獲得數據庫連接,這就是我使用數據庫的方式,因爲沒有問題。Zend Framework 2&PHPUnit - 模擬Zend Db Adapter Adapter類
我現在正試圖學習如何在Zend應用程序上使用PHPUnit,並且因爲我無法模擬Zend\Db\Adapter\Adapter
類而在測試映射器中的函數時遇到了困難。
This tutorial在Zend網站上顯示模擬數據庫連接,但它使用Zend\Db\TableGateway\TableGateway
類。我在網上找到的所有其他教程使用此類過了,唯一的事情,我發現關於Zend\Db\Adapter\Adapter
類是this:
$date = new DateTime();
$mockStatement = $this->getMock('Zend\Db\Adapter\Driver\Pdo\Statement');
$mockStatement->expects($this->once())->method('execute')->with($this->equalTo(array(
'timestamp' => $date->format(FormatterInterface::DEFAULT_DATETIME_FORMAT)
)));
$mockDbDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\Pdo\Pdo')
->disableOriginalConstructor()
->getMock();
$mockDbAdapter = $this->getMock('Zend\Db\Adapter\Adapter', array(), array($mockDbDriver));
$mockDbAdapter->expects($this->once())
->method('query')
->will($this->returnValue($mockStatement));
我試圖把該爲我的setUp
的方法,但在運行phpunit
測試類給了我以下錯誤:
Fatal error: Call to a member function createStatement() on null in C:\Program Files (x86)\Zend\Apache2\htdocs\test_project\vendor\zendframework\zend-db\src\Sql\Sql.php on line 128
所以我的問題是,你怎麼嘲笑了PHPUnit中Zend\Db\Adapter\Adapter
類?
我見過this question這是類似的,但採用的是Zend/Db/Adapter/AdapterInterface
相反,我似乎無法代碼翻譯成我的情況。映射器和測試類代碼如下。
ProductMapper.php:
public function __construct(Adapter $dbAdapter) {
$this->dbAdapter = $dbAdapter;
$this->sql = new Sql($dbAdapter);
}
public function fetchAllProducts() {
$select = $this->sql->select('products');
$statement = $this->sql->prepareStatementForSqlObject($select);
$results = $statement->execute();
$hydrator = new ClassMethods();
$product = new ProductEntity();
$resultset = new HydratingResultSet($hydrator, $product);
$resultset->initialize($results);
$resultset->buffer();
return $resultset;
}
ProductMapperTest.php:
public function setUp() {
$date = new DateTime();
$mockStatement = $this->getMock('Zend\Db\Adapter\Driver\Pdo\Statement');
$mockStatement->expects($this->once())->method('execute')->with($this->equalTo(array(
'timestamp' => $date->format(FormatterInterface::DEFAULT_DATETIME_FORMAT)
)));
$mockDbDriver = $this->getMockBuilder('Zend\Db\Adapter\Driver\Pdo\Pdo')->disableOriginalConstructor()->getMock();
$this->mockDbAdapter = $this->getMock('Zend\Db\Adapter\Adapter', array(), array(
$mockDbDriver
));
$this->mockDbAdapter->expects($this->once())->method('query')->will($this->returnValue($mockStatement));
}
public function testFetchAllProducts() {
$resultsSet = new ResultSet();
$productMapper = new ProductMapper($this->mockDbAdapter);
$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
}
編輯#1:
關注從張伯倫的回答荷蘭國際集團,我改變了我的映射器使用Sql
類的構造函數,並改變了我的測試類:
public function setUp() {
$mockSelect = $this->getMock('Zend\Db\Sql\Select');
$mockDbAdapter = $this->getMockBuilder('Zend\Db\Adapter\AdapterInterface')->disableOriginalConstructor()->getMock();
$this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\Pdo\Statement');
$this->mockSql = $this->getMock('Zend\Db\Sql\Sql', array('select', 'prepareStatementForSqlObject'), array($mockDbAdapter));
$this->mockSql->method('select')->will($this->returnValue($mockSelect));
$this->mockSql->method('prepareStatementForSqlObject')->will($this->returnValue($this->mockStatement));
}
public function testFetchAllProducts() {
$resultsSet = new ResultSet();
$this->mockStatement->expects($this->once())->method('execute')->with()->will($this->returnValue($resultsSet));
$productMapper = new ProductMapper($this->mockSql);
$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
}
不過,現在我得到以下錯誤:
ProductTest\Model\ProductMapperTest::testFetchAllProducts Failed asserting that two variables reference the same object.
哪個來自$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
。我是否歪曲了一些不正確的東西?
編輯#2:
正如威爾特建議,我改變了測試類使用StatementInterface
嘲笑一個語句來代替,所以代碼現在看起來像:
public function setUp() {
$mockSelect = $this->getMock('Zend\Db\Sql\Select');
$mockDbAdapter = $this->getMockBuilder('Zend\Db\Adapter\AdapterInterface')->disableOriginalConstructor()->getMock();
$this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
$this->mockSql = $this->getMock('Zend\Db\Sql\Sql', array('select', 'prepareStatementForSqlObject'), array($mockDbAdapter));
$this->mockSql->method('select')->will($this->returnValue($mockSelect));
$this->mockSql->method('prepareStatementForSqlObject')->will($this->returnValue($this->mockStatement));
}
public function testFetchAllProducts() {
$resultsSet = new ResultSet();
$this->mockStatement->expects($this->once())->method('execute')->with()->will($this->returnValue($resultsSet));
$productMapper = new ProductMapper($this->mockSql);
$this->assertSame($resultsSet, $productMapper->fetchAllProducts());
}
但是測試用例仍然如上所述失敗。我沒有改變嘲弄execute
方法的代碼行,因爲我相信它已經返回$resultsSet
,但是我可能是錯的!
偉大的答案謝謝,指出我在正確的方向改變依賴使用'Sql'實例。我現在已經擺脫了錯誤信息,但測試本身沒有達到我期望的效果。如果你不介意看看,我已經爲這個問題添加了新的代碼?我不確定我是否嘲笑了某些錯誤,或者僅僅是缺乏單元測試的經驗,並且我錯誤地認爲測試通過了! – crazyloonybin
@Crazyloonybin使用'StatementInterface'來模擬語句就足夠了(不需要爲此需要特定的適配器類)。然後你需要在這個'$ mockStatement'中模擬'execute'方法,並且這個方法的返回值應該是'$ resultsSet'。然後你的測試應該通過。 – Wilt
我已經改變了語句以讀取'$ this-> mockStatement = $ this-> getMock('Zend \ Db \ Adapter \ Driver \ StatementInterface');'但我仍然收到同樣的錯誤。我保留'$ this-> mockStatement'代碼與問題編輯中顯示的代碼相同,'testFetchAllProducts'函數返回'$ resultsSet' - 此行是否也需要修改? – crazyloonybin