用DI进行单元测试

问题描述:

我有一个关于依赖注入的问题。到目前为止,我一直保持简单,我的方法主要是将对象创建分解出来,然后将其传递给构造器。我已经到了一个要攻击需要多个Oble的较大类的地步。有些甚至包含其他物体的物体,在这里和那里都有快乐的小单身人士。它在测试这些类时会变得很难看,因为它们远离“孤立”,它们仍然被硬编码到它们的依赖关系。用DI进行单元测试

所以。注入一个对象或2为一个微不足道的类是直截了当,

我已经看着依赖容器,看到了很多实现,现在想知道什么是使用容器与注册表的好处例如。难道不能像使用注册表那样容易地使用匿名函数来创建所需的依赖关系吗?

我偷看到的2个容器,Php DependencyPimple在实现上差别很大。

我想知道用户容器与传递直线对象的优点。我无法理解如何测试php-dependency的实现,也就是说如何在phpunit中实现模拟数据库对象而不需要在测试时注入实际的类?有依赖映射出来并用在这样的doctags中有利吗?

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']); 
}; 

声明共享ressources始终服务于同一个实例(单!?):

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

这是我用一个简单的注册表保存或者对象或匿名函数的概念。我是否错过了这种方法?疙瘩,我可以看到如何测试,但从测试的角度来看,Php-Dependency对我来说还不清楚。

通常,在我们的应用,我们做的构造函数注入和定义一个接口在我们的系统中所有组件:

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'); 

而容器注入所有需要的依赖s进入对象。

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

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

更新: 我添加了一个在容器中布线的例子。

+0

我认为这就是stefgosselin所在的位置,并且想知道如何选择DI策略。 – 2011-05-22 19:05:04

+0

当你运行你的测试时,它是如何被@var Db_AdapterInterface覆盖的模拟?我想我现在明白了,只是想确认我是否理解正确:你的组件有一个模拟/存根等价物,DI容器在测试时被加载,交给调用测试? – stefgosselin 2011-05-22 22:26:44

+0

问题是为了澄清从这种方法中获得的东西与使用注册表加载对象并传递对象(如新的$ book = Book($ registry-> get('Db_Adapter'));看起来好像一些容器只是作为注册机构。 – stefgosselin 2011-05-22 22:40:46