用DI进行单元测试

时间:2011-05-22 11:31:48

标签: php unit-testing phpunit

我有一个关于依赖注入的问题。到目前为止,我一直保持简单,我的方法基本上是在对象中创建对象并在构造函数中传递它。我已经到了一个点,我正在攻击需要多个oblects的大型类。有些甚至还有包含其他物体的物体,这里和那里都有快乐的小单身。在测试这些类时,它变得非常难看,因为它们远非“孤立”,它们仍然是硬编码到它们的依赖项。

因此。为一个普通的类注入一个对象或2是很简单的,

我已经查看了依赖容器,看到了很多实现,现在我想知道使用容器与注册表有什么好处。难道不能轻易地使用注册表来保存在调用时创建所需依赖项的匿名函数吗?

我偷看的2个容器Php DependencyPimple在实施方面有很大不同。

我想知道用户容器与传递直接对象的优势。我不明白如何测试php-dependency的实现,即如何在phpunit中实现mock数据库对象而不测试实际的类?将依赖关系映射出来并在像这样的文档中使用是否有优势?

Class Book {

  private $_database;

  /**
   * @PdInject database
   */
  public function setDatabase($database) {
      $this->_database = $database;
  }

}
另一方面,疙瘩采取了完全不同的方法。没有docblock标签,在单独的文件中没有映射,它似乎是某种加强的注册表....

  Objects are defined by anonymous functions that return an instance of the object:

 // define some parameters
 $container['cookie_name'] = 'SESSION_ID';
 $container['session_storage_class'] = 'SessionStorage';

......可以同时表现为工厂:

$container['session'] = function ($c) {
    return new Session($c['session_storage']);
};

声明共享资源总是服务于同一个实例(singleton!?):

$c['session'] = $c->share(function ($c) {
return new Session($c['session_storage']);
});

这是我想到使用一个包含对象或匿名函数的简单注册表。我在这种方法中遗漏了什么?疙瘩,我可以看到如何测试,但从测试的角度来看,我不清楚Php-Dependency。

1 个答案:

答案 0 :(得分:2)

通常在我们的应用程序中,我们进行构造函数注入并为系统中的所有组件定义接口:

class Book
{
    /**
     * @var Db_AdapterInterface
     */
    private $_database;

    public function __construct(Db_AdapterInterface $database)
    {
        $this->_database = $database;
    }
}

我们当然有一个标准的Db_Adapter,然后是另一个Db_TestAdapter。在Db_TestAdapter中,我们可以在测试中定义SQL查询的结果。

对于我们的普通应用,我们的容器有这样的东西:

$container->add('Db_AdapterInterface', new Db_Adapter());

然后在我们的测试中,我们改为使用这一行:

$container->add('Db_AdapterInterface', new Db_TestAdapter());

要获取图书的实例,我们只需向容器询问:

$book = $container->construct('Book');

容器将所有必需的依赖项注入对象。

如果你保持所有对象松散耦合,即对象A只需要一个接口B,那么你总是可以为对象A提供一个测试实现。那时你使用的容器并不重要。

我们有一个非常简单的IoC容器,可以进行基本的构造函数注入。我们的测试继承自使用标准测试对象填充容器的基类。这样我们就没有很多代码来构造我们想要测试的对象。

<强>更新 我添加了一个在容器中连接的示例。