gmock设置默认操作/ ON_CALL与EXPECT_CALL

Nic*_*tti 46 c++ googlemock

在使用它来指定默认操作时,我不明白ON_CALL和EXPECT_CALL之间的区别.

到目前为止,我注意到/了解到有两种方法可以调整模拟的默认操作:

ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));
Run Code Online (Sandbox Code Playgroud)

要么

EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释一下:

  • 两种方法的区别
  • 每个人的起伏
  • 什么时候适合使用它们(什么样的设置...)

Vla*_*sev 48

这两个陈述之间存在微妙但重要的差异.EXPECT_CALL设置模拟调用的期望.写作

EXPECT_CALL(mock, methodX(_)).WillRepeatedly(do_action);
Run Code Online (Sandbox Code Playgroud)

告诉gMock methodX可以mock使用任何参数多次调用,并且当它出现时,mock将执行do_action.另一方面,

ON_CALL(mock, methodX(_)).WillByDefault(do_action);
Run Code Online (Sandbox Code Playgroud)

告诉gMock,无论什么时候methodX被调用mock,都应该执行do_action.在您必须在模拟上写下许多期望的情况下,该功能很有用,并且大多数/所有这些都必须指定相同的操作 - 特别是如果它很复杂.您可以在其中指定该操作ON_CALL,然后EXPECT_CALL在不明确指定操作的情况下编写s.例如,

ON_CALL(mock, Sign(Eq(0), _))
  .WillByDefault(DoAll(SetArgPointee<1>("argument is zero"), Return(0)));
ON_CALL(mock, Sign(Gt(0), _))
  .WillByDefault(DoAll(SetArgPointee<1>("argument is positive"), Return(1)));
ON_CALL(mock, Sign(Lt(0), _))
  .WillByDefault(DoAll(SetArgPointee<1>("argument is negative"), Return(-1)));
Run Code Online (Sandbox Code Playgroud)

现在,如果你必须写很多EXPECT_CALLs,你不必mock每次都指定行为:

EXPECT_CALL(mock, Sign(-4, _));
EXPECT_CALL(mock, Sign(0, _));
EXPECT_CALL(mock, Sign(1, _)).Times(2);
EXPECT_CALL(mock, Sign(2, _));
EXPECT_CALL(mock, Sign(3, _));
EXPECT_CALL(mock, Sign(5, _));
Run Code Online (Sandbox Code Playgroud)

在另一个例子中,假设Sign返回int,如果你写

ON_CALL(mock, Sign(Gt(0), _)).WillByDefault(Return(1));
EXPECT_CALL(mock, Sign(10, _));
Run Code Online (Sandbox Code Playgroud)

该调用mock.Sign(10)将返回1作为ON_CALL指定的调用的默认行为EXPECT_CALL.但如果你写

EXPECT_CALL(mock, Sign(Gt(0), _).WillRepeatedly(Return(1));
EXPECT_CALL(mock, Sign(10, _));
Run Code Online (Sandbox Code Playgroud)

mock.Sign(10, p)将返回0 的调用.它将与第二个期望匹配.该期望指定没有明确的操作,gMock将为其生成默认操作.该默认操作是返回返回类型的默认值,该值为0 int.在这种情况下,第一个期望将被完全忽略.

  • 是的,如 https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md#using-multiple-expectations 中所述,稍后定义的期望值会覆盖之前对匹配调用的期望值。 (2认同)

BЈо*_*вић 11

ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));
EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));
Run Code Online (Sandbox Code Playgroud)

正如你所说,这两条线完全相同,因此根本没有差异.您可以使用任一方式设置默认操作.

但是,存在逻辑差异:

  • ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01)); 表示可能会调用该方法,如果发生这种情况,则每次调用都将返回0x01
  • EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01)); 意味着预期将调用该方法,并且每次调用都将返回0x01

顺便说一句,在他们的备忘单中有一个设置默认操作,其中说:

要自定义特定方法的默认操作,请使用ON_CALL():

ON_CALL(mock_object, method(matchers))
    .With(multi_argument_matcher)  ?
    .WillByDefault(action);
Run Code Online (Sandbox Code Playgroud)

  • @Nicoretti不,它不起作用.我甚至不确定如果你设置两者会发生什么.也许在那种情况下只有一个被执行.顺便说一句,gtest有[section](http://code.google.com/p/googlemock/wiki/CheatSheet#Setting_Default_Actions)解释如何设置默认行为. (2认同)

Nad*_*m Z 8

ON_CALL这是关于和gMock CookbookEXPECT_CALL中解释的最重要差异的“官方”解释。

定义模拟对象的行为基本上有两种构造:ON_CALLEXPECT_CALL

区别?

ON_CALL 定义了当调用模拟方法时会发生什么,但并不暗示对被调用的方法有任何期望

EXPECT_CALL 不仅定义了行为,还设置了一个期望,即必须使用给定的参数调用该方法给定的次数(并且当您指定顺序时也按给定的顺序)

既然EXPECT_CALL做得更多,不是比更好吗ON_CALL

并不真地。每个都会EXPECT_CALL对被测代码的行为添加约束。过多的约束是不好的——甚至比没有足够的约束更糟糕。

这可能是违反直觉的。验证较多的测试怎么会比验证较少的测试更糟糕呢?验证不是测试的全部目的吗?

答案在于测试应该验证什么。 良好的测试可以验证代码的契约性。如果测试过度指定,就不会为实现留下足够的自由度。 因此,在不破坏契约的情况下改变实现(例如重构和优化),这应该是完全可以做到的,但可能会破坏此类测试。然后你必须花时间修复它们,但在下次实现更改时却会看到它们再次损坏。

请记住,无需在一项测试中验证多个属性。事实上,在一次测试中只验证一件事是一种很好的风格。如果这样做,一个错误可能只会破坏一两个测试,而不是几十个(您更愿意调试哪种情况?)。如果您还习惯为测试提供描述性名称来告诉它们验证的内容,那么您通常可以轻松地从测试日志本身猜出问题所在。

ON_CALL因此默认使用,并且仅EXPECT_CALL在您实际打算验证调用是否已进行时才使用。