Moq中的单元测试Mock/Stub定义

14
任何关于单元测试的阅读或建议都明确区分了Mock和Stub的定义。我目前的理解是:
Mock:一种伪造的对象,用于你的测试并进行最终断言。
Stub:一种伪造的对象,用于在测试中隔离依赖项但不进行断言。
然而,Moq似乎只允许创建Mocks。该框架中的Stub命名空间似乎已经过时,并推荐使用Mock.SetupXXX。
我的理解是否有误?或者有没有普遍认为mock对象仅仅可以被用作stub的情况?
也许我太苛求了,只是我一直发现编程语言非常严格,而且更喜欢正确使用它,尤其是当其他开发人员可能接手项目时。
4个回答

18
根据Moq项目网站,Moq提供:
使用简单的MockBehavior枚举实现对模拟行为的细粒度控制(无需学习模拟、存根、伪装、动态模拟等之间的���论区别)。
模拟、存根等之间的缺乏区别是一种有意为之的设计决策;这是我个人喜欢的设计决策。如果我需要一个真正���模拟,则调用其上的Verify()。否则,就没有Verify()。我喜欢这种简单性,也没有发现自己想念mockstub之间的差异。

11

马丁·福勒(Martin Fowler)撰写了一篇好文章,《Mock不是Stub》,我认为这篇文章很清楚地阐述了它们之间的区别。

Mock用于行为验证,而Stub提供虚假数据并通常参与状态验证。


但行为验证涉及到所涉及的数据,即使这些数据以不同的方式保存。当然,术语是清晰定义的,但这并不意味着在区分明显模糊的情况下不需要灵活性。 - eglasius
1
@eglasius 当然。如果一个库认为它给我一个模拟,但是我想把它当作存根使用,我不会有任何问题。我只需要将变量命名为我所需即可。 - Don Roby
+1 绝对同意,如果团队认为沟通这个区别很重要,那么变量的命名将会澄清这一点。 - eglasius

3

个人认为这只是一个有点儿愚蠢的讨论。

重要的是在测试中使用模拟/存根来断言你需要的内容,不要断言你不需要的内容。


1
我不同意eglasius的观点。测试应该非常易读,易于理解其他开发人员正在执行什么操作。语言在其中起着关键作用。 - William
@WDuffy 当然可以,但我认为这已经在测试代码中清楚地表达出来了。 - eglasius
将存根与模拟对象区分开来有助于向测试读者表明哪些消息与当前测试(期望)相关,哪些是附带的(存根)。 - Gishu

0

确实,Moq可以创建真正的存根。从Moq快速入门页面中了解更多:

* Setup a property so that it will automatically start tracking its value (also known as Stub):

  // start "tracking" sets/gets to this property
  mock.SetupProperty(f => f.Name);

  // alternatively, provide a default value for the stubbed property
  mock.SetupProperty(f => f.Name, "foo");


  // Now you can do:

  IFoo foo = mock.Object;
  // Initial value was stored
  Assert.Equal("foo", foo.Name);

  // New value set which changes the initial value
  foo.Name = "bar";
  Assert.Equal("bar", foo.Name);

* Stub all properties on a mock (not available on Silverlight):

  mock.SetupAllProperties();

以我个人的意见,对于伪装品的区别最好将其视为伪装品的功能而不是类型之间的区别,因为一个伪装品可以同时扮演多个角色(例如,既能是真实模拟器又能是破坏者),而对于使用模拟框架来说并不需要这样的区分。(我应该写一篇博文讨论这个问题!)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接