Gmock 设置默认操作/ON_CALL 与 EXPECT_CALL

我不明白 ON _ CALL 和 EXPECT _ CALL 之间的区别 指定默认操作。

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

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

或者

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

谁能给我解释一下:

  • 这两种方法的区别
  • 每个人的起起落落
  • 什么时候适合使用它们(什么样的设置... ...)
120040 次浏览
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);

这两个语句之间存在细微但显著的差异。 EXPECT_CALL设置模拟调用的期望值

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

告诉 gMock methodX可以在 mock上用任何参数调用任意次数,当它被调用时,mock将执行 do_action。另一方面,

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

告诉 gMock 无论何时在 mock上调用 methodX,它都应该执行 do_action。在需要在模拟上编写许多期望的场景中,这个特性非常有用,而且大多数/所有期望都必须指定相同的操作——特别是当操作很复杂时。您可以在 ON_CALL中指定该操作,然后在不显式指定该操作的情况下编写 EXPECT_CALL。例如:

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_CALL,你不必每次都指定 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_CALLEXPECT_CALL指定的调用提供默认行为。但如果你写

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

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

看这里 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 不仅定义了行为,而且还设置了一个期望,即在给定的次数(以及在指定顺序时的给定顺序) ,将使用给定的参数调用该方法。

一个区别是 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设置了已定义的默认行为。

下面是关于 ON_CALLEXPECT_CALL之间最重要的差异的“官方”解释,如 GMock 食谱中所解释的。

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

有什么区别吗?

ON_CALL 定义调用模拟方法时发生的情况,但不意味着对被调用的方法有任何期望.

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

既然 EXPECT_CALLON_CALL做的更多,它是不是比 ON_CALL好?

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

这可能有悖常理。验证更多的测试怎么会比验证更少的测试更糟糕呢?验证不就是测试的全部意义吗?

答案在于测试应该验证什么。因此,在不打破协议的情况下改变实现(例如重构和优化)(这应该是完全可以做到的)可以打破这样的测试。然后,您必须花时间修复它们,只有在下一次实现更改时才会看到它们再次崩溃。

Keep in mind that one doesn't have to verify more than one property in one test. In fact, it's a good style to verify only one thing in one test. If you do that, a bug will likely break only one or two tests instead of dozens (which case would you rather debug?). If you are also in the habit of giving tests descriptive names that tell what they verify, you can often easily guess what's wrong just from the test log itself.

因此,默认情况下使用 ON_CALL,并且只有在实际想要验证调用是否发生时才使用 EXPECT_CALL