在模仿框架网站上给出的大多数例子都是模仿界面。假设我现在使用的是NSubstitute,他们所有的模拟示例都是模拟接口。
但在现实中,我看到的是一些开发人员模拟的混凝土类。是否建议模拟混凝土类?
发布于 2012-08-30 06:52:10
从理论上讲,模拟一个具体的类绝对没有问题;我们正在针对一个逻辑接口(而不是关键字interface)进行测试,并且该逻辑接口是由class还是interface提供的并不重要。
在实践中,.NET/C#使得这有点问题。正如您提到的.NET模拟框架,我将假定您受到该框架的限制。
在.NET/C#中,成员在默认情况下是非虚拟的,因此任何基于代理的模拟行为方法(即从类派生,并覆盖所有成员以执行特定于测试的内容)都不会起作用,除非您显式地将成员标记为virtual。这会导致一个问题:您正在使用一个在单元测试中应该是完全安全的模拟类的实例(即,不会运行任何真正的代码),但是除非您已经确保一切都是virtual的,否则您可能会以运行真实代码和模拟代码的混合结束(如果有构造函数逻辑,这可能会特别有问题,构造逻辑总是运行,如果有其他具体的依赖项需要新的依赖关系,则会复合)。
有几种方法可以解决这个问题。
interfaces。这是有效的,也是我们在NSubstitute documentation中的建议,但它的缺点是可能会使您的代码库膨胀,因为实际上可能并不需要这些接口。可以说,如果我们在代码中发现了良好的抽象,我们自然会得到整洁、可重用的接口,我们可以对其进行测试。我还没见过这样的结果,但YMMV。:)针对最后一个想法的一个常见抱怨是,您正在通过“假”接缝进行测试;我们正在超越通常用于扩展代码的机制,以更改代码的行为。需要走出这些机制可能表明我们的设计是僵化的。我理解这一论点,但我见过创建另一个接口的噪音超过好处的情况。我想这是一个意识到潜在的设计问题的问题;如果你不需要来自测试的反馈来突出设计的刚性,那么它们是很好的解决方案。
我要抛出的最后一个想法是在我们的测试中改变单元的大小。通常,我们将单个类作为一个单元。如果我们有许多内聚类作为我们的单元,并让接口作为该组件周围定义良好的边界,那么我们就可以避免模拟尽可能多的类,而只需在更稳定的边界上模拟。这可以使我们的测试变得更加复杂,好处是我们正在测试功能的内聚单元,并鼓励围绕该单元开发可靠的接口。
希望这能有所帮助。
发布于 2013-03-02 02:09:02
更新:
3年后,我想承认我改变了主意。
从理论上讲,我仍然不喜欢仅仅为了方便模拟对象的创建而创建接口。在实践中(我使用的是NSubstitute)使用Substitute.For<MyInterface>()比模拟一个有多个参数的真实类要容易得多,例如Substitute.For<MyCLass>(mockedParam1, mockedParam2, mockedParam3),其中每个参数都应该单独模拟。其他潜在问题在NSubstitute documentation中进行了描述
在我们公司,现在推荐的做法是使用接口。
原始答案:
如果您不需要创建同一抽象的多个实现,请不要创建接口。由于它的pointed by David Tchepak,你不想膨胀你的代码库的接口,实际上可能并不需要。
来自http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstractions.aspx
你是否从你的类中提取接口来实现松散耦合?如果是,你可能会有一个实现它们的1:1 relationship between your interfaces and the concrete classes。这很可能是not a good sign,并违反了Reused Abstractions Principle (RAP)。
一个给定接口只有一个实现的是一种代码嗅觉。
如果你的目标是可测试性,我更喜欢David Tchepak's answer above的第二个选项。
然而,我不相信你必须让一切都变得虚拟。只需将您要替换的方法设为虚拟就足够了。我还将在方法声明旁边添加一个注释,说明方法是虚的,这只是为了使它可以替代单元测试模拟。
但是,请注意,替换具体类而不是接口有一些限制。例如,for NSubstitute
注意:不会为类创建递归替换,因为创建和使用类可能会产生不必要的副作用
。
发布于 2012-08-29 17:11:31
问题是:何乐而不为呢?
我可以想出几个场景,在其中这是有用的,例如:
具体类的实现还没有完成,或者做它的人是不可靠的。因此,我模拟指定的类,并根据它测试代码。
它对模拟执行数据库访问之类的操作的类也很有用。如果您没有测试数据库,那么您可能希望为测试返回始终为常量的值(这可以通过模拟类来轻松实现)。
https://stackoverflow.com/questions/12174304
复制相似问题