在.Net应用程序中包含单元测试时的设计注意事项?

时间:2011-03-04 08:09:08

标签: c# .net unit-testing

默认情况下,.Net中的所有方法都被视为final。除非使用虚拟修饰符。 Java是另一种方式。所有方法都是虚拟的,可以覆盖。当涉及使用Moq,RhinoMock等框架进行单元测试时,我们可以创建模拟或存根。如果我们要创建一个mock,我们需要一个接口。如果没有必要只是为了能够测试我们的代码,这迫使我们在任何地方使用接口。

另一方面,我们可以创建存根,但是我们要存根的方法需要是虚拟的,以便框架可以覆盖它们。

还有其他一些使用AOP的模拟框架,比如TypeMock,但我不确定如果有这么好的开源和免费软件,我可以在这样的框架上花钱。

我知道非虚拟和接口方法都稍慢。但这不应该真正影响当今硬件上的应用程序。

所以我的问题是:几乎所有东西都应该是一个接口,即使它没有真正封装某种行为?或者我们应该根据需要创建虚拟方法以帮助我们进行测试。对我来说,两个人都觉得有点笨拙和不必要。

你有什么想法?

3 个答案:

答案 0 :(得分:3)

就我个人而言,我发现使用依赖接口可以改善设计。它清楚地表明了您所依赖的内容,而不仅仅是实现类恰好暴露的公共和内部方法。

请注意,这并不意味着每个类都需要有一个接口......只是那些您希望充当依赖关系的接口。例如,我不会为主要是“简单数据”或异常的类型创建接口。但是如果一个类在某些方面充当“服务”,那么界面感觉是合适的。如果有一种更简单的方式来表达该界面而不是拥有一个单独的文件会很好,但从概念上讲我觉得它很干净。

(这个观点让我有点过时了,我意识到,但它有助于了解我的设计,至少:)

答案 1 :(得分:2)

我倾向于将我的解决方案划分为具有明确定义的责任区域的组件,例如一组类和其他类型一起工作以解决某些特定问题。构成这种组件的公共外观的类通常从接口中受益匪浅,因为它允许我轻松地替换或存储它们以进行测试和一般维护。是否仅为了单元测试而为内部使用的类添加接口是一个决定,通常由内部复杂性决定,以及组件本身是否使用了需要被删除的其他组件。

为类创建一个接口非常简单,因为Visual Studio甚至内置了必要的重构选项(右键单击,重构 - >提取接口)。因此,创建界面的编码工作有点微不足道(假设设计是由类最终看起来驱动的)。

虽然随着时间的推移,维护界面需要付出一些努力,但我发现自己经常使用它们。它减少了API的公共表面,使维护更容易,如果你有像R#这样的工具,那么几乎不需要额外的工作。

还值得一提的是,TypeMock和Moles(Pex伴侣)都加入了分析API。因此它与AOP有些不同,即使它们提供类似AOP的功能。当您需要拦截静态方法或常规字段访问时,这些非常有用,您无法使用接口建模。

答案 2 :(得分:0)

我一般发现我通常使用接口编写代码,以便在具体类型之间松散耦合,控制反转和依赖注入,并有助于测试。

然而,就像你说的那样,创建界面的时候可能是噪音。在这些特定场景中,您需要权衡是否

  1. 设计正确
  2. 你实际上需要能够模拟/存根类型
  3. 将成员标记为虚拟会损害设计
  4. 将介绍一个有助于设计的界面
  5. (我同时考虑3和4)

    如果你发现你确实需要能够模拟/存根类型,那么对于大多数框架,你需要提供一些能够做到这一点的机制,虚拟成员和接口是两个明显的选择。

    不需要界面或虚拟成员的模拟和存根框架是TypemockMoles,我相信JustMock。前两个使用profiling API(我相信JustMock也这样做),它基本上将方法调用重定向到您已定义的其他位置。关于能否做到这一点是一件好事有一些争论,因为它可能意味着你不得不少考虑设计,但有时候它确实可以提供帮助(DateTime.Now是典型的例子)。 / p>