C# 测试依赖于企业库的代码,即使它没有';你不提供接口吗?

C# 测试依赖于企业库的代码,即使它没有';你不提供接口吗?,c#,unit-testing,dependency-injection,enterprise-library,C#,Unit Testing,Dependency Injection,Enterprise Library,也许我对依赖项注入和测试缺乏了解,但我不明白对不实现接口的类使用依赖项注入如何帮助我进行测试 例如,在EnterpriseLibrary5.0文档中,它谈到了使用Unity容器创建实例。它说,这有助于“可测试性:在使用依赖项注入样式时,将类与依赖项隔离是很简单的。” 我如何在我的单元测试夹具中使用它?他们的示例中有一个构造函数,其参数作为类而不是接口: public class TaxCalculator { private ExceptionManager _exceptionManag

也许我对依赖项注入和测试缺乏了解,但我不明白对不实现接口的类使用依赖项注入如何帮助我进行测试

例如,在EnterpriseLibrary5.0文档中,它谈到了使用Unity容器创建实例。它说,这有助于“可测试性:在使用依赖项注入样式时,将类与依赖项隔离是很简单的。”

我如何在我的单元测试夹具中使用它?他们的示例中有一个构造函数,其参数作为类而不是接口:

public class TaxCalculator 
{
  private ExceptionManager _exceptionManager;
  private LogWriter _logWriter;

  public TaxCalculator(ExceptionManager em, LogWriter lw) 
  {
    this._exceptionManager = em;
    this._logWriter = lw;
  }
}

最好是针对抽象而不是实现进行编程。但抽象并不总是接口。它可以是抽象类

public abstract class LogWriter
{
    public abstract void Write(string message);
}
因此,创建抽象类的mock没有问题:

Mock<LogWriter> logWriter = new Mock<LogWriter>();
TaxCalculator calc = new TaxCalculator(logWriter.Object);
Mock logWriter=new Mock();
TaxCalculator calc=新的TaxCalculator(logWriter.Object);
如果您不进行单元测试,我认为传递非抽象参数没有任何问题,因为YAGNI原则。如果我不需要ExceptionManager的另一个实现,那么我为什么要在它上面创建抽象呢?但若我使用TDD,那个么我肯定需要至少两个类的实现。一个真实和一个模拟/存根

顺便说一句,要小心


更新:不知道您指的是Microsoft.Practices.EnterpriseLibrary的现有类(我不喜欢)。我认为这是微软实践团队的又一次设计失败。使“密封”的ExceptionManager类不实现任何接口/基类会降低可测试性。

只要您的类未密封,一个合格的模拟框架就可以创建一个子类,其行为与模拟接口实现完全相同。当您依赖于具体的类时,需要考虑更多的因素-
密封的
方法仍将在指定的类上执行,等等。-但是一般来说,它与依赖于接口没有什么不同。

要回答“如何测试企业库代码”的问题:您不需要。测试别人的东西是别人的工作。企业库或任何其他第三方库中的任何接口或抽象都是为了自己的抽象目的而存在的,而不是为了您的抽象目的

您需要做的是定义自己的接口来描述应用程序的需求(日志记录、缓存、加密等),然后编写适配器,使用企业库(或其他第三方库)实现您的接口。这种做法被称为

为了测试您自己以这种方式设计的代码,对于单元/组件级测试,您只需对您自己定义的接口(例如IMyOwnLogger)使用测试双倍。要测试为适应第三方库而编写的适配器,您需要编写集成测试。为了测试所有这些功能是否协同工作,您需要编写验收测试,以推动应用程序通过UI或皮下注射


有关此视图的更多信息,请查看我的文章:“.

我更改了标题以反映这样一个事实,即我不想测试企业库,而是想测试依赖于企业库的我自己的代码。我更新了答案,以明确说明如何根据外部依赖性测试自己的代码。顺便说一句,定义描述应用程序需求的自己的接口(例如日志记录)听起来不错。将基础架构与业务代码分离是非常好的。但失去酷炫的框架功能,增加另一个抽象级别,失去优化和性能,绝对不是好事。如果你的应用程序不需要框架功能,你也不会失去框架功能。遵循良好的设计方法,您应该首先定义应用程序需要什么,然后将该设计中的任何外部依赖项调整到可用的框架中。以这种方式继续下去,你永远不会得到一个你需要的功能,但不知何故却被切断了。我不是建议您编写最低公分母接口,而是建议您编写应用程序所需的接口。至于适配器模式在某种程度上对你的应用程序有害,我个人还没有看到。@DerekGreer你的文章博客现在是一个垃圾网站。另一方面,由于web archive项目,您可以看到原始内容:第三方库中的摘要是为了自己的目的而存在的,而不是为您提供要使用的摘要。此外,企业库可能是使用sealed关键字的最佳方案。P&P一直说,他们不打算直接使用EL,而是想作为编写代码的示例。他们不希望人们扩展他们的东西,然后在以后的版本中进行设计更改时抱怨。所以,你认为log4net中的ILog并不是为了给我提供一个可使用的抽象概念吗?如果你愿意,就把这句话当作夸张吧。不同的软件供应商出于不同的原因提供接口。有时,接口作为供应商测试方法的副产品出现。其他情况下,可能会有一个更高级别的组件所依赖的多个实现。一些供应商可能将接口作为seam提供,希望在不修改公共接口的情况下允许将来的设计更改发生变化。是的,有些人可能会提供接口,认为这将是一个抽象来管理它们。无论如何,你不应该在自己的设计中依赖它们。ExceptionManager不是密封的。事实上,它(以及Entlib中的其他*manager类)是抽象类,专门用于允许模拟。仅仅因为它们不是接口并不意味着它们不是抽象。