是否建议模拟具体课程? [英] Is it recommended to mock concrete class?

查看:65
本文介绍了是否建议模拟具体课程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在模拟框架网站上给出的大多数示例都是模拟接口.假设我当前正在使用NSubstitute,他们所有的模拟示例都是模拟接口.

Most of the examples given in mocking framework website is to mock Interface. Let say NSubstitute that I'm currently using, all their mocking examples is to mock interface.

但是实际上,我看到一些开发人员模拟了具体的类.建议模拟具体课程吗?

But in reality, I saw some developer mock concrete class instead. Is it recommended to mock concrete class?

推荐答案

从理论上讲,模拟具体类绝对没有问题.我们正在针对逻辑接口(而不是关键字interface)进行测试,并且该逻辑接口是由class还是interface提供都没有关系.

In theory there is absolutely no problem mocking a concrete class; we are testing against a logical interface (rather than a keyword interface), and it does not matter whether that logical interface is provided by a class or interface.

在实践中,.NET/C#有点问题.正如您提到的.NET模拟框架一样,我将假设您仅限于此.

In practice .NET/C# makes this a bit problematic. As you mentioned a .NET mocking framework I'm going to assume you're restricted to that.

在.NET/C#中,成员默认情况下是非虚拟的,因此除非您明确指定,否则任何基于代理的模拟行为方法(即派生自类,并覆盖所有成员以进行特定于测试的工作)将不起作用将成员标记为virtual.这就导致了一个问题:您正在使用模拟类的实例,该实例在单元测试中应该是完全安全的(即不会运行任何实际代码),但是除非您确保所有内容都为virtual,否则您可能会最终会混合运行真实代码和模拟代码(如果存在始终运行的构造函数逻辑,而如果要重新构建其他具体依赖关系,则情况尤其复杂).

In .NET/C# members are non-virtual by default, so any proxy-based methods of mocking behaviour (i.e. derive from the class, and override all the members to do test-specific stuff) will not work unless you explicitly mark the members as virtual. This leads to a problem: you are using an instance of a mocked class that is meant to be completely safe in your unit test (i.e. won't run any real code), but unless you have made sure everything is virtual you may end up with a mix of real and mocked code running (this can be especially problematic if there is constructor logic, which always runs, and is compounded if there are other concrete dependencies to be new'd up).

有几种方法可以解决此问题.

There are a few ways to work around this.

  • 使用interfaces.这是可行的,这是我们在 NSubstitute文档中建议的内容,但缺点是可能会使您的代码库膨胀与可能实际上不需要的接口.可以说,如果我们在代码中找到良好的抽象,那么我们自然会得到可以测试的整洁,可重用的接口.我还没有看到它像那样成功推出,但是YMMV. :)
  • 努力使所有内容变为虚拟.当我们真的只想更改整个类的行为以进行测试时,建议将所有这些成员用作设计中的扩展点,这可能是一个缺点.它还不会停止构造函数逻辑的运行,如果具体的类需要其他依赖项,它也不会有所帮助.
  • 通过类似 Virtuosity加载项之类的 TypeMock (付费)JustMock (付费) Microsoft Moles ,是免费的)或 Prig (免费+开源).我相信它们能够模拟类的所有方面以及静态成员.
  • Use interfaces. This works and is what we advise in the NSubstitute documentation, but has the downside of potentially bloating your codebase with interfaces that may not actually be needed. Arguably if we find good abstractions in our code we'll naturally end up with neat, reusable interfaces we can test to. I haven't quite seen it pan out like that, but YMMV. :)
  • Diligently go around making everything virtual. An arguable downside to this is that we're suggesting all these members are intended to be extension points in our design, when we really just want to change the behaviour of the whole class for testing. It also doesn't stop constructor logic running, nor does it help if the concrete class requires other dependencies.
  • Use assembly re-writing via something like the Virtuosity add-in for Fody, which you can use to modify all class members in your assembly to be virtual.
  • Use a non-proxy based mocking library like TypeMock (paid), JustMock (paid), Microsoft Fakes (requires VS Ultimate/Enterprise, though its predecessor, Microsoft Moles, is free) or Prig (free + open source). I believe these are able to mock all aspects of classes, as well as static members.

一个关于最后一个想法的常见抱怨是,您正在通过假"接缝进行测试;我们超出了通常用于扩展代码以更改代码行为的机制.需要走出这些机制可能表明我们的设计很僵化.我理解这个论点,但是我已经看到了创建另一个接口带来的好处超过收益的情况.我想这是意识到潜在设计问题的问题.如果您不需要测试的反馈来突出设计的刚性,那么它们就是很好的解决方案.

A common complaint lodged against the last idea is that you are testing via a "fake" seam; we are going outside the mechanisms normally used for extending code to change the behaviour of our code. Needing to go outside these mechanisms could indicate rigidity in our design. I understand this argument, but I've seen cases where the noise of creating another interface/s outweighs the benefits. I guess it's a matter of being aware of the potential design issue; if you don't need that feedback from the tests to highlight design rigidity then they're great solutions.

我要提出的最后一个想法是改变测试中单元的大小.通常,我们将一个类作为一个单元.如果我们有许多内聚类作为单元,并且接口在该组件周围充当了明确定义的边界,那么我们可以避免不得不模拟尽可能多的类,而只需要模拟更稳定的边界.这会使我们的测试变得更加复杂,其优势在于我们正在测试功能性的统一单元,并鼓励我们围绕该单元开发可靠的接口.

A final idea I'll throw out there is to play around with changing the size of the units in our tests. Typically we have a single class as a unit. If we have a number of cohesive classes as our unit, and have interfaces acting as a well-defined boundary around that component, then we can avoid having to mock as many classes and instead just mock over a more stable boundary. This can make our tests a more complicated, with the advantage that we're testing a cohesive unit of functionality and being encouraged to develop solid interfaces around that unit.

希望这会有所帮助.

这篇关于是否建议模拟具体课程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆