使用Soley接口来促进单元测试中的顽固和模拟现在已经过时了?

Mat*_*att 12 .net unit-testing interface mocking

在.NET中,TypeMock Isolator和Microsoft Moles允许隔离任何类,属性或方法 - 无论是密封的,静态的,受保护的还是非虚拟的.所以在Moq或Rhino Mocks中不可能嘲笑,现在不再是这样了.

我总是对使用接口只是为了能够允许模拟的想法感到厌恶,否则只有具体的类存在.在这个视图中我并不孤单(见这里,这里这里).在后者中暗示"现代"模拟框架不再需要用于测试或依赖注入的接口.

然而,虽然我不能说TypeMock Isolator,但我可以说在Microsoft Moles中使用Mocks非常慢.在单元测试中使用如下代码会使测试速度太慢而无法经常使用:

MFile.ReadAllLinesString = (s) => csvDataCorrectlyFormatted;
MDirectoryInfo.AllInstances.GetFilesString = (di,fi) => fileInfoArray;
MFileInfo.AllInstances.NameGet = (fi) => "Doesn't Matter";
Run Code Online (Sandbox Code Playgroud)

我敢肯定,如果正在测试的方法被编程到接口或抽象基类(以便文件系统代码可以在各种包装中抽象出来),那么使用像Moq这样的框架来进行存根或模拟最终会更快.但是,我们又回到了基本上增加单元测试能力的生产代码复杂性的情况.

我倾向于认为Isolator和Moles只有在不能用传统的模拟框架模拟时才能使用.然而,为了测试,我仍然为添加生产代码复杂性这一概念而苦苦挣扎.

我很好奇社区其他人的想法.

更新10/06/10:通过说我为了测试而增加了生产代码复杂性的概念,我指的是在不需要时添加接口(或抽象类),例如,当使具体类非密封时,虚拟方法会做.后者仍然允许接缝进行测试.即使后来发现需要为多个实现使用接口,他们也不能从类中提取它吗?但除非出现这种需要,否则为什么不跟随YAGNI.

我全都采用SOLID原则,它们使程序的体系结构更易于维护.我不认为在每种情况下都需要虔诚地遵循这些原则.我认为咒语"它总是取决于",多次发挥作用.否则,即使只有一个实现,也会留下具有接口或抽象基类的每个具体类型.

最后,我不是说,因为Isolator和Moles允许人们在基于动态代理的框架中克服隔离限制,人们不应该将架构设计为可维护的.在许多情况下,SOLID原则是最好的,因此不需要隔离器或摩尔.这是接口仅用于我正在质疑的测试的情况.我也提出了关于速度的另一个观点.如果选择使用隔离器和摩尔,它似乎会带来速度惩罚.所以我当然不认为他们使基于动态代理的框架过时了.

Tho*_*ler 5

这确实是一个有趣的问题,我有时从测试新手那里听到。在我看来,Moles/Typemock 并不能与模拟框架相提并论,它们肯定不是替代品。以下是我的主要论据:

  • 尽管每一分钱都物有所值,但 Typemock 的初始许可成本很高(每个席位约 800 美元),这就是为什么有些管理人员不愿投入这么多钱的原因。另一方面,Moles 是免费的,但需要相当多的工作来设置 Moles 程序集,并且带有一个非常奇怪的“API”,这很难学习 - 特别是如果您完全不熟悉测试。
  • Typemock 和 Moles 不是严格意义上的“模拟框架”——它们是某种分析器,在幕后使用运行时检测。因此,它们对性能产生了相当大的影响。我没有这方面的具体数字,但根据我自己的经验,我估计仪器测试要慢 100-400%(Typemock 似乎比 MS Moles 快)!对于包含数千个测试的大型测试电池,这本身可能是一个障碍。
  • 最后同样重要的是,致命的论点:模拟框架不仅迫使您使用接口,而且还迫使您在软件上应用高度解耦和可维护的设计(沿着SOLID的路线)。- 请记住:软件的最初编写并不是主要的成本,而是维护!- 使用 Typemock 或 Moles,您基本上可以为所欲为,这确实是一件坏事,也是反对使用 Typemock 或 Moles 开发的主要论点。

结论:

  • 如果你想用测试覆盖一个棕地项目,而这个项目根本没有考虑到可测试性,那么你必须使用 Typemock 或 Moles 之一(在我看来,Typemock 是更好的选择)。
  • 如果你正在开始一个新项目(即你正在做一个绿地项目),然后使用模拟框架(我个人喜欢Moq,因为它的简单性)并使用 MS Moles 作为你无法拥有界面的东西的补充用于(例如 .NET 框架类型)。

甚至 Typemock 的首席开发人员 Roy Osherove 也是这么说的(希望他不会因此而与他的老板惹上麻烦):一位客户改用 MOQ—— 我很高兴

但是,有一个例外:如果从头开始学习测试驱动开发,即使是新代码,使用 Typemock 也可能是有益的。通过这种方式,您可以显着拉平 TDD 学习曲线......

托马斯

  • 当项目的架构将受益于松散耦合(即层、带 IoC 容器的 DI、AOP 等)时,我完全支持使用接口。关于这个问题,我更多指的是当架构不调用接口并且添加一个接口的唯一原因是为了模拟。我知道你可以说我仍然有更多的灵活性,但是 YAGNI 原则呢? (3认同)

Igo*_*aka 4

一点也不。从纯粹的技术角度来看,这些接口并不是绝对必要的。模拟框架构造模拟的唯一要求是方法是虚拟的并且类型具有可访问的构造函数。当我知道某个特定的类不会有多个实现时,我会经常使用它。

我更喜欢使用基于普通 Castle Dynamic Proxy 的模拟框架进行 TDD。这一切都是为了创建一个具有适当放置的测试接缝的松散耦合系统。这些测试接缝将来可能会成为可扩展点。模拟考虑因素提出的要求强化了良好的设计实践,从而导致编写更有针对性的类。