【发布时间】:2017-06-27 06:55:12
【问题描述】:
几年前我跟随this tutorial 开始学习Zend 框架。在那里,它显示映射器是使用 Zend\Db\Adapter\Adapter 类创建的以获取数据库连接,这就是我使用数据库的方式,因为没有任何问题。
我现在正在尝试学习如何在 Zend 应用程序上使用 PHPUnit,但在测试映射器中的函数时遇到了困难,因为我无法模拟 Zend\Db\Adapter\Adapter 类。
Zend 网站上的This tutorial 显示模拟数据库连接,但它使用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 会出现以下错误:
致命错误:调用 C:\Program Files (x86)\Zend\Apache2\htdocs\test_project\vendor\zendframework\zend-db\src\Sql\Sql.php 中的成员函数 createStatement() on null第 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:
根据 Wilt 的回答,我将映射器更改为在构造函数中使用 Sql 类,并将我的 Test 类更改为:
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 断言两个变量引用同一个对象失败。
来自$this->assertSame($resultsSet, $productMapper->fetchAllProducts()); 行。我是不是嘲笑错了什么?
编辑#2:
按照 Wilt 的建议,我将测试类更改为使用 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,但是我可能错了!
【问题讨论】:
标签: unit-testing zend-framework zend-framework2 mocking phpunit