c++ gmock设置默认操作/ ON_CALL与EXPECT_CALL

cfh9epnr  于 2023-03-20  发布在  其他
关注(0)|答案(6)|浏览(818)

当使用ON_CALL和EXPECT_CALL来指定默认操作时,我不明白它们之间的区别。
到目前为止,我注意到/了解到有两种方法可以调整mock的默认动作:

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

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

有人能给我解释一下吗:

  • 两种方法的区别
  • 每一个的起唐斯
  • 何时适合使用它们(什么样的设置...)
0g0grzrc

0g0grzrc1#

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

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

告诉gMock可以使用任何参数在mock上调用methodX任意次,并且当它被调用时,mock将执行do_action

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

告诉gMock,无论何时在mock上调用methodX,它都应该执行do_action。当您必须在mock上编写许多期望,并且其中大多数/所有期望都必须指定相同的操作时,该特性非常有用--特别是当它很复杂时。您可以在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_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。在这种情况下,第一个期望将被完全忽略。

093gszye

093gszye2#

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);
hwamh0ep

hwamh0ep3#

下面是gMock Cookbook中对ON_CALLEXPECT_CALL之间最重要区别的“官方”解释。
基本上有两种结构用于定义模拟对象的行为:ON_CALLEXPECT_CALL
有什么不同?
ON_CALL定义了调用mock方法时会发生什么,但并不意味着对被调用的方法有任何期望
EXPECT_CALL不仅定义了行为,而且还设置了一个期望值,即必须使用给定的参数调用该方法给定的次数(如果指定了顺序,则以给定的顺序)
既然EXPECT_CALL做得更多,它不是比ON_CALL更好吗?
不完全是。每个EXPECT_CALL都对测试代码的行为添加了一个约束。约束太多是不好的--甚至比没有足够的约束更糟糕。
这可能是违反直觉的。验证更多的测试怎么会比验证更少的测试更糟糕呢?验证不就是测试的全部意义吗?
答案在于测试应该验证什么。**一个好的测试验证代码的契约。如果测试过度指定,它就没有给实现留下足够的自由。**因此,在不破坏契约的情况下更改实现(例如重构和优化),这应该是非常好做的,可以打破这样的测试。然后你必须花时间修复它们,只是在下一次改变实现时看到它们再次被破坏。
请记住,一个人不必在一个测试中验证多个属性。事实上,在一个测试中只验证一个东西是一种好的风格。如果你这样做,一个bug可能只会破坏一两个测试,而不是几十个测试(您更愿意调试哪种情况?)如果您还习惯于给测试起描述性的名字来告诉它们验证什么,您通常可以很容易地从测试日志本身猜出问题所在。

因此,默认情况下使用ON_CALL,并且只有在您实际打算验证是否已进行调用时才使用EXPECT_CALL

ycl3bljg

ycl3bljg4#

请参见此处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不仅定义了行为,而且还设置了一个期望,即该方法将被使用给定的参数调用给定的次数(当你指定了顺序时,也会以给定的顺序调用)。

r1zk6ea1

r1zk6ea15#

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

6gpjuf90

6gpjuf906#

我感到困惑的是,没有一个答复提到最重要的一个词:无趣的呼叫
EXPECT_CALL表示函数调用是相关的/有趣的。如果期望的函数调用与您的规范不匹配(调用次数、参数等),则这是一个失败的期望,导致测试用例失败。
如果ON_CALL被使用而没有任何EXPECT_CALL在各自的函数上,那么这表明函数是“无趣的”,并且进一步的行为很大程度上取决于我们使用的mock类型(strict/naggy/nice),其范围从忽略调用到测试用例失败.
EXPECT_CALL用于测试目的所必需的内容,ON_CALL用于指定您需要的操作,以便在测试代码中导航,并且,如果没有特别要求,通过跳过EXPECT_CALL和ON_CALL来避免过度指定不相关的函数(并使用GMock定义的默认行为)。

相关问题