虽然有足够的资源,即使是在SO上,但在这些Q / A中,只有两个术语相互比较。
那么,简而言之,他们每个人都是什么?它们如何相互关联?或者根本不是吗?
答案 0 :(得分:19)
模拟和存根之间的区别非常简单 - mock可以使测试失败,而存根不能。这就是全部。此外,您可以将存根视为提供值的内容。如今,假冒只是两者的通用术语(稍后会详述)。
让我们考虑一种情况,您必须构建一个通过通信协议发送包的服务(具体细节无关紧要)。您只需使用包代码提供服务,剩下的就完成了。鉴于下面的代码片段,您能否确定哪个依赖关系将成为存根以及哪个模拟潜在的单元测试?
public class DistributionService
{
public double SendPackage(string packageCode)
{
var contents = this.packageService.GetPackageContents(packageCode);
if (contents == null)
{
throw new InvalidOperationException(
"Attempt to send non-exisiting package");
}
var package = this.packageBuilder.Build(contents);
this.packageDistributor.Send(package);
}
}
很容易判断packageBuilder
只是提供了价值,并且没有任何可能的方法可以使任何测试失败。这是一个存根。即使它看起来更模糊,packageService
也是存根。它提供了一个值(我们对该值的处理与存根的观点无关)。当然,稍后我们将使用该值来测试是否抛出异常,但它仍然在我们的控制范围内(因为,我们告诉存根确切地做什么而忘记它 - 它应该对测试没有进一步的影响)。
与packageDistributor
不同。即使它提供任何价值,它也不会消耗掉。然而,对Send
的调用似乎是我们实施的非常重要的一部分,我们很可能希望验证它被调用。
此时我们应该得出packageDistributor
是模拟的结论。我们将有一个专门的单元测试断言Send
方法被调用,如果由于某些原因它不是 - 我们想要知道,因为它是整个过程的重要部分。其他依赖项是存根,因为它们只是为其他可能更相关的代码片段提供值。
Stub是存根,可以在天真实现中替换为常量值:
var contents = "Important package";
var package = "<package>Important package</package>";
this.packageDistributor.Send(package);
这实际上是模拟框架对存根的作用 - 指示它们返回可配置/显式值。 老派,手工存根通常就是这样 - 返回常量值。
显然,这样的代码没有多大意义,但任何曾经做过TDD的人在课堂开发的早期阶段肯定会看到一堆这样的天真的实现。由TDD产生的迭代开发通常有助于识别您的类的依赖关系。
在这篇文章的开头我提到 fake 只是一个通用术语。鉴于mock也可以作为存根(特别是在涉及现代模拟框架时),为了避免混淆,最好将这样的对象称为假的。如今,你可以看到这种趋势在不断增长 - 原始的模拟 - 存根区别正逐渐成为过去,并且使用了更多的通用名称。例如:
答案 1 :(得分:6)
Mock和Stub都被称为假对象。在我看来:
Stub用于替换外部依赖项,它使我们的测试运行无异常。我们必须使用Assert来确定测试是否失败。 Stub仅适用于测试某些功能是否正确的结果
模拟更复杂,通常用于测试行为,例如验证是否是一个被称为
答案 2 :(得分:2)
它们通常可以互换,但我认为存在细微差别。