【问题标题】:Is there a standard method for unit testing code where dependencies do not implement interfaces?在依赖项不实现接口的情况下,是否有用于单元测试代码的标准方法?
【发布时间】:2013-05-28 13:07:42
【问题描述】:

对于依赖不实现接口的单元测试代码,是否有标准方法?例如,System.Net.Http 命名空间只公开具体的类。如果我试图对依赖于System.Net.Http 中的一个具体类的类进行单元测试,我是否应该只构造一个实例,例如HttpRequestMessage,设置它的属性,然后将这个新构造的对象提供给系统正在测试中?继承HttpRequestMessage 并让它实现一个自定义接口然后可以被模拟/存根是否有意义?

【问题讨论】:

  • 使用依赖项进行测试时,您希望控制这些依赖项。子类化/抽象不是必需的。你真正想要做的是存根你的依赖,让它按照你的测试对象期望的方式运行。

标签: c# .net unit-testing


【解决方案1】:

推荐的做法是将此对象包装在您创建的一个类中,该类本身实现一个接口。然后,您将在代码中使用此包装器类,然后您可以提供此包装器的模拟版本来代替真实的类​​。您不会使用此方法对其进行子类化,而是包含它并使用委托(不要与委托混淆!)来转发每个方法。

例如,您可以创建一个继承自 IHttpRequestMessage 的类 HttpRequestMessageWrapper(您定义的,包括 HttpRequestMessage 的所有公共属性。虽然您可能只实现您使用的属性就可以解决问题)。

或者,您可以使用支持 shim 的测试框架,该框架本质上为您完成此包装,并用 shim 版本替换对对象的调用。 Microsoft Fakes(在 VS 2012 MS 测试中引入)就是这样做的。

Shims 通常用于替换常见的框架调用,例如 DateTime.Now,以便您可以在测试期间提供特定值。

【讨论】:

  • 谢谢。这是有道理的,并且应该让我能够灵活地在将来更改 HttpRequestMessageWrapper 之类的内部工作,而不会违反任何合同。
  • @BradfordFisher - 这不会真正改变类的内部工作,尽管它可以更容易地替换通过接口调用的特定功能。您正在包装的类将不了解您的包装器。我建议不要更改包装类的行为,因为这可能会导致各种意外问题。
【解决方案2】:

我建议你看看:AutoFixture http://autofixture.codeplex.com/ 它可以帮助你以你想要的方式构造对象。在您的示例 HttpRequestMessage 中,您可以自定义夹具:fixture.Customize<HttpRequestMessage>(c => {}); 在单元测试中有很多使用 AutoFixture 的例子。或者您可以在此处发布您想要测试的代码,我可以尝试提供帮助。

【讨论】:

  • Autofixture 对大多数框架类没有帮助,因为您必须能够存根功能。例如,如何使用 Autofixture 帮助存根 Socket 类?它只会对本质上是 POCO 的课程有所帮助。
  • 完全同意你的看法。没有适用于所有情况的银小母鸡。在 AutoFixture 中,您可以设置要使用的模拟框架。我同意您上面的回答,但我发现自己在大多数情况下可以使用 AutoFixture + RhinoMock(或 Moq)进行单元测试。至少在我做过的项目中。
  • AutoMocking 仅适用于接口和抽象类,问题的关键是如何测试使用不实现这些的具体类的类。
【解决方案3】:

另一个测试遗留代码的好工具是Typemock

【讨论】:

    猜你喜欢
    • 2023-04-09
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 2017-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多