也许我表现出对依赖注入和测试缺乏理解,但我不明白如何使用依赖注入与不实现接口的类有助于我进行测试?
例如,在Enterprise Library 5.0文档中,它讨论了使用Unity容器创建实例。它说这有助于“可测试性:在使用依赖注入样式时,将类与依赖关系隔离起来是微不足道的。” MSDN
如何在我的单元测试装置中使用它?他们的示例有一个构造函数,其参数为类而不是接口:
public class TaxCalculator
{
private ExceptionManager _exceptionManager;
private LogWriter _logWriter;
public TaxCalculator(ExceptionManager em, LogWriter lw)
{
this._exceptionManager = em;
this._logWriter = lw;
}
}
答案 0 :(得分:9)
要回答“如何测试企业库代码”这个问题:您没有。测试其他人的东西是其他人的工作。 Enterprise Library或任何其他第三方库中的任何接口或抽象都是出于自己的抽象目的而存在,而不是为您自己的。
您需要做的是定义自己的接口,描述应用程序的需求(日志记录,缓存,加密等),然后编写使用Enterprise Library(或其他第三方库)实现接口的适配器。这种做法称为Dependency Inversion Principle。
要测试以这种方式设计的代码,对于单元/组件级别测试,您只需将Test Doubles用于您自己定义的接口(例如IMyOwnLogger)。要测试您编写的适配器以适应第三方库,您可以编写集成测试。要测试它是否一起工作,您可以编写通过UI或皮下驱动应用程序的验收测试。
有关此视图的详细信息,请查看我的文章:“TDD Best Practices: Don't Mock Others”。
答案 1 :(得分:4)
最好是针对抽象而不是实现进行编程。但抽象并不总是接口。它可以是抽象类。
public abstract class LogWriter
{
public abstract void Write(string message);
}
因此,创建抽象类的模拟没有问题:
Mock<LogWriter> logWriter = new Mock<LogWriter>();
TaxCalculator calc = new TaxCalculator(logWriter.Object);
如果您没有进行单元测试,由于YAGNI原则,我认为传递非抽象参数没有任何问题。如果我不需要ExceptionManager的另一个实现,那么我为什么要在它上面创建抽象呢?但是如果我做TDD,那么我肯定需要至少两个类的实现。一个真实的和一个模拟/存根。
请注意service locator anti-pattern。
更新:没有得到你指的是现有的Microsoft.Practices.EnterpriseLibrary类(我不喜欢)。我认为这是Microsoft.Practices团队的另一个设计失败。使'密封'的ExceptionManager类没有实现任何接口/基类会导致可测试性。
答案 2 :(得分:3)
只要你的类不是sealed
,一个称职的模拟框架就可以创建一个类似于模拟接口实现的子类。当你依赖于具体的类时,还有更多的考虑因素 - sealed
方法仍将在指定的类上执行,等等 - 但一般它与依赖于接口的情况没有什么不同