2

我正在尝试在管理数据库连接的类上使用 TDD。然而

  • 我经常远离数据库可用的网络进行开发
  • 我只想测试不与真实连接混淆的类,即使是 SQLite:memory:
  • 我可能想以独立于平台的方式测试连接(例如,将 PDO 对象交换为 MySQLi 对象等)。尤其是数据库不全是 MySQL,有些是 SQLServer。

基本上我想这样做:

class ConnectionManager {
    ...
    public function getConnection($name) {
        $params = $this->lookup($name);
        return new \PDO($params['spec'], $params['username'], $params['password']);
    }
}

在我的测试运行器中:

class ConnectionManagerTest extends \PHPUnit_Framework_TestCase {
    public function testGetConnection() {
        $cxn = new ConnectionManager(); 
        $this->assertNotNull($cxn->getConnection('test')); // or whatever
    }
}

不知何故,我想使用 PDO 类的模拟。我唯一的选择是向测试类构造函数或其方法之一添加显式参数吗?我已经尝试按照 Mockery 文档使用“实例模拟”,但由于我使用自动加载导致“致命错误无法重新声明类”(duh)。

我不想用纯粹用于测试的代码污染合同,但这是我唯一的选择吗?

谢谢你的帮助

4

1 回答 1

3

这看起来像是依赖注入可以帮助您的情况。网上有很多很好的文章描述了这种技术(这里是维基百科概述),这个先前的堆栈溢出答案给出了对该技术的简明解释(示例是用 Java 编写的,但它应该解释模式并且可以转移到另一个语言很容易)。

您关于“不想用纯粹用于测试的合同污染代码”的观点很有趣。我想你会发现,随着你对 TDD 的了解越来越多,编写易于测试的代码和编写好的干净代码本质上是同一枚硬币的两个方面。TDD 的一个微妙的力量(如果实践得当)是它引导你走向一个好的、干净的设计,可以很容易地随着你的应用程序增长。通过遵循将测试置于代码设计核心的方法,您实际上是从客户的角度设计代码,这会导致代码中不同组件的接口更清晰,并最终使使用这些接口的代码更清晰。

依赖注入是遵循 TDD 时常用的技术,并且很好地说明了这些要点。一方面它对测试很有效,因为它允许您在测试时轻松交换组件,这样您就可以避免调用数据库、模拟和验证组件之间的交互等。但是,它也支持一般良好的设计,因为它引导您走向低耦合和灵活的设计(例如,如果您对数据库进行依赖注入访问,那么将数据源从数据库更改为其他数据库变得相当简单技术)。

于 2013-08-10T14:27:08.240 回答