64

我不明白使用 ON_CALL 和 EXPECT_CALL 指定默认操作时的区别。

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

ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));

或者

EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));

有人可以向我解释一下:

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

5 回答 5

69

两种说法之间存在细微但显着的差异。EXPECT_CALL对模拟电话设定期望。写作

EXPECT_CALL(mock, methodX(_)).WillRepeatedly(do_action);

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

ON_CALL(mock, methodX(_)).WillByDefault(do_action);

告诉 gMock 无论何时methodX调用 on 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)));

现在,如果你必须写很多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, _));

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

ON_CALL(mock, Sign(Gt(0), _)).WillByDefault(Return(1));
EXPECT_CALL(mock, Sign(10, _));

该调用mock.Sign(10)将返回 1,因为ON_CALL它为由 指定的调用提供了默认行为EXPECT_CALL。但是如果你写

EXPECT_CALL(mock, Sign(Gt(0), _).WillRepeatedly(Return(1));
EXPECT_CALL(mock, Sign(10, _));

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

于 2012-12-19T17:40:35.717 回答
13
ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));
EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));

正如您所说,这两行所做的事情完全相同,因此根本没有区别。根据需要使用任何一种方式设置默认操作。

但是,有一个逻辑上的区别:

  • 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);
于 2012-12-18T13:23:04.213 回答
4

这是gMock Cookbook中解释的关于ON_CALL和之间最重要区别的“官方”解释。EXPECT_CALL

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

区别?

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

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

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

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

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

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

请记住,不必在一次测试中验证多个属性。事实上,在一次测试中只验证一件事是一种很好的风格。如果你这样做,一个错误可能只会破坏一两个测试而不是几十个(你宁愿调试哪种情况?)。如果您还习惯于给测试起描述性名称来说明它们所验证的内容,那么您通常可以很容易地从测试日志本身中猜出问题所在。

所以ON_CALL默认使用,并且仅EXPECT_CALL在您真正打算验证调用是否已进行时使用。

于 2021-08-25T13:36:46.377 回答
1

见这里https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md#knowing-when-to-expect-useoncall

基本上有两种构造来定义模拟对象的行为:ON_CALL 和 EXPECT_CALL。区别?ON_CALL 定义了调用模拟方法时会发生什么,但并不意味着对被调用的方法有任何期望。EXPECT_CALL 不仅定义了行为,还设置了一个期望,即使用给定的参数调用该方法给定的次数(并且在您指定顺序时也以给定的顺序)。

于 2020-02-06T06:10:43.080 回答
0

一个区别是ON_CALL行为(默认行为)和EXPECT_CALL期望的清除方式不同。

https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md#verifying-and-resetting-a-mock

using ::testing::Mock;
...
// Verifies and removes the expectations on mock_obj;
// returns true if and only if successful.
Mock::VerifyAndClearExpectations(&mock_obj);
...
// Verifies and removes the expectations on mock_obj;
// also removes the default actions set by ON_CALL();
// returns true if and only if successful.
Mock::VerifyAndClear(&mock_obj);

这可用于在您的测试中清除预期,但仍保持模拟对象的默认行为。请注意,对象并非如此,StrictMock因为它们不允许测试在没有实际期望的情况下通过,即使使用ON_CALL.

于 2020-02-25T07:31:29.863 回答