【问题标题】:Dependency Injection and Unit test this constructor依赖注入和单元测试这个构造函数
【发布时间】:2011-05-19 11:18:26
【问题描述】:
我在类中有一个构造函数和一个属性:
private IMyCollectionObjects _myCollectionObjects;
public MyClassConstructor(string message)
{
_myCollectionObjects = MyCollection.GetCollectionObejects(message);
}
请尽可能详细地帮助我了解如何单元测试这个构造函数
和 GetCollectionObjects 方法?
如何完全解耦
上课?你可以给出答案
使用任何 IoC,我想
理解这个概念。
谢谢。
【问题讨论】:
标签:
unit-testing
dependency-injection
c#-4.0
【解决方案1】:
总之,单元测试是关于单一测试的,也就是说,一次只做一件事。
您能否详细说明一下如何单元测试此构造函数和GetCollectionObjects 方法?
首先,您是否对MyCollection 课程进行了单元测试?
如果没有,你应该从它开始,因为你的MyClassConstructor 类依赖它,这是依赖注入的基础。否则,你怎么知道你得到的结果是对还是错?您将无法测试并确保它完美运行。
如何完全解耦类?您可以使用任何 IoC 给出答案,我想了解这个概念。
我的拙见,您必须有明确的理由使用依赖注入使一个对象依赖于另一个对象。一旦你让一个对象依赖于另一个对象,在我看来,将它们解耦是没有意义的。一种解耦方式可能是使用企业库的 Unity Application Block。
对该构造函数进行单元测试
在测试这样的构造函数时,您通常只需要检查三件事。
- 构造函数不返回空值;
- 它返回的实例是预期的类型;
- 您希望通过其依赖项实例化的对象实际上已被实例化。
[测试用例(“消息”)]
公共无效DependentConstructorTest(字符串消息){
MyClassConstructor myclass= new MyClassConstructor(message);
断言.IsNotNull(myclass);
Assert.IsInstanceOf(typeof(MyClassConstructor), myclass);
Assert.IsNotNull(myclass.MyCollection); // 其中 MyCollection 表示的属性
// 暴露创建的对象实例
// 你的 MyClassConstructor 类所依赖的。
}
注意:这个测试是使用 NUnit 属性和断言方法编写的。使用任何你喜欢的东西。
【解决方案2】:
这大概是您需要做的事情(有一些假设)。
假设 MyCollection 是一个静态类并且 GetCollectionObjects 解析一个字符串并返回一个 IMyCollectionObjects,您首先需要使 MyCollection 非静态,并将其传递给构造函数。类中使用的静态类/方法根据定义或多或少会产生紧密耦合。
现在您将构建传递消息字符串和 MyCollection 的类。您的构造函数结合使用这两者来填充 IMyCollectionObjects 类型的成员变量。为了确保这按预期发生,您将需要一种从类外部检查结果的方法(即公共方法)。因此,您将需要一个公开 _myCollectionObjects 的属性获取器。
现在您只需要从一个或多个测试中调用此构造函数,并在构造后检查属性以确保成功将字符串解析为集合。
请注意,这实际上更像是一个集成测试,而不是一个离散的单元测试。您确实在测试解析是否成功。如果此处表示的类确实是您要测试的,那么测试实际上只是检查 GetCollectionObjects 是否被调用。该调用的结果确实无关紧要,因为您(可能)会有一个单独的测试或一组测试来确保 MyCollection 上的 GetCollectionObjects 方法按预期工作。
【解决方案3】:
对诸如GetCollectionObjects 等静态成员的依赖很难测试,因为您无法在运行时替换它的实现。这意味着您无法将MyClassConstructor 的实例与GetCollectionObjects 的实现细节完全隔离开来。如果没有隔离测试目标,就不能真正算是单元测试。
See here for further discussion of static dependencies.
您可以重构此代码以完全解耦(因此完全可测试):
private readonly IMyCollectionObjects _myCollectionObjects;
public MyClassConstructor(IMyCollectionObjects myCollectionObjects)
{
_myCollectionObjects = myCollectionObjects;
}
这使有关如何将消息转换为集合的知识直接从MyClassConstructor 中冒出来,使类更简单、更有凝聚力且耦合度更低。