php - 绑定(bind)到实现细节的数据库单元测试

标签 php unit-testing dependency-injection zend-framework2 phpunit

我有一个简单的 PHP 类,它包装了对数据库的访问以检索用户并希望对其进行单元测试。我目前有以下代码:

要测试的类:

class UserTable {

    protected $tableGateway;

    public function __construct(\Zend\Db\TableGateway\TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
    }

    public function getUserWithId($id) {
        return $this->tableGateway->select(['id' => $id])->current();
    }
}

单元测试:

class UserTableTest extends \PHPUnit_Framework_TestCase {
    public function testGetUserWithIdReturnsCorrectUser() {
        $user = new User();

        $resultSet = new ResultSet();
        $resultSet->initialize([$user]);

        $mockTableGateway = $this->getMock('\Zend\Db\TableGateway\TableGateway', ['select'], [], '', false);
        $mockTableGateway->expects($this->once())->method('select')->with(['id' => 1])->willReturn($resultSet);

        $userTable = new UserTable($mockTableGateway);

        $this->assertEquals($user, $userTable->getUserWithId(1));
    }
}

但是,现在如果我后来决定更改我使用表网关的方式(例如使用 select(['id = ?' => $id]),单元测试将会失败。这将单元测试绑定(bind)到应该避免的 getUserWithId($id) 的实现细节。

防止单元测试依赖于实现细节的最佳实践是什么?是否值得努力建立一个单元测试可以运行的实际测试数据库(这也会大大减慢测试的执行速度),或者是否有更好的方法来模拟表网关?

最佳答案

不要模拟不属于您的代码!* 对于使用数据库的类,您必须编写集成测试。好处是这将迫使您将数据库访问与其他逻辑分开。

*这是来自“在测试的指导下开发面向对象的软件”一书的实际建议,以我自己为使用 Doctrine 的实体管理器的代码编写测试的经验为后盾

关于php - 绑定(bind)到实现细节的数据库单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25930627/

相关文章:

typescript - Nestjs 依赖注入(inject) - 将服务注入(inject)服务

dependency-injection - 如何将 AutoMApper.5.2.0 与 Ninject 一起使用?

javascript - 加载后向外部网页添加 HTML/JS 代码

PHP 和 ajax 没有更新

php - MySQL 查询在 phpmyadmin 中工作,但在 php 中不工作

java - 是否有适用于 MongoDB 的 DbUnit 替代方案?

c# - 列出或发现单元测试未涵盖的方法

Ruby:从二维数组中的每个子数组中获取第 n 个元素

php - 使用 php 和 Tumblr API 发布到 Tumblr

.net - 如何在不涉及表示层(即 View 模型)的情况下在 WPF 应用程序中注入(inject)非表示依赖项(如存储库)?