首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ZendFramework2& PHPUnit -模拟Zend\Db\Adapter\Adapter类

ZendFramework2& PHPUnit -模拟Zend\Db\Adapter\Adapter类
EN

Stack Overflow用户
提问于 2017-02-09 10:09:59
回答 1查看 1.2K关注 0票数 6

几年前,我在本教程之后开始学习Zend。在这里,它显示了使用Zend\Db\Adapter\Adapter类创建映射程序以获得数据库连接,这就是我从那时起就一直使用数据库的方式。

我现在正在学习如何在Zend应用程序上使用PHPUnit,并且在测试映射器中的函数时遇到了困难,因为我无法模拟Zend\Db\Adapter\Adapter类。

Zend上的本教程显示模拟数据库连接,但它使用Zend\Db\TableGateway\TableGateway类。我在网上找到的所有其他教程也使用这个类,我发现关于Zend\Db\Adapter\Adapter类的唯一东西是

代码语言:javascript
复制
$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会给出以下错误:

致命错误:调用行128上的C:\Program (x86)\Zend\Apache2\htdocs\test_project\vendor\zendframework\zend-db\src\Sql\Sql.php中null的成员函数createStatement()

所以我的问题是,如何在Zend\Db\Adapter\Adapter?中嘲弄类?

我已经看到了类似的这个问题,但是使用了Zend/Db/Adapter/AdapterInterface,而且我似乎无法将这些代码转换成我的情况。下面是Mapper和测试类代码。

ProductMapper.php:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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类,并将测试类更改为:

代码语言:javascript
复制
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来模拟语句,因此代码现在如下所示:

代码语言:javascript
复制
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,但是我可能错了!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-09 11:41:09

也许在这里最好将__construct方法更改为将Sql实例作为参数。$dbAdapter似乎只在构造函数中使用,因此,在我看来,ProductMapper类的实际依赖不是Adapter实例,而是Sql实例。如果您做了这样的更改,您只需要在您的Sql中模拟ProductMapperTest类。

如果您不想在代码中进行这样的更改,并且仍然希望继续为当前的ProductMapper类编写测试,那么还应该模拟Sql类内部调用的Adapter类的所有其他方法。

现在,您可以在$this->sql->prepareStatementForSqlObject($select);实例上调用Sql实例,该实例内部调用Adapter类的createStatement方法(您可以看到班级)。但是在您的示例中,Adapter是一个模拟,这就是抛出错误的原因:

致命错误:在C:\Program Files (x86)\Zend\Apache2\htdocs\test_project\vendor\zendframework\zend-db\src\Sql\Sql.php on 128中调用null的成员函数

因此,要解决这个问题,您应该模拟这个方法,类似于您对query方法的模拟:

代码语言:javascript
复制
$mockStatement = //...your mocked statement...
$this->mockDbAdapter->expects($this->once())
                    ->method('createStatement')
                    ->will($this->returnValue($mockStatement));

在下一行中,您将调用$statement->execute();,这意味着您还需要在$mockStatement中模拟execute方法。

正如您所看到的,编写这个测试变得非常麻烦。你应该问问自己,你是否走上了正确的道路,测试了正确的组件。您可以进行一些小的设计更改(改进),以便更容易地测试ProductMapper类。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42133746

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档