gmock 设置默认操作 / ON_CALL vs. EXPECT_CALL
gmock setting default actions / ON_CALL vs. EXPECT_CALL
我不明白使用它来ON_CALL和EXPECT_CALL之间的区别 指定默认操作。
到目前为止,我注意到/了解到有两种方法可以调整模拟的默认动作:
ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));
或
EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));
有人可以向我解释一下:
- 两种方法的区别
- 每个人的起起落落
- 什么时候适合使用它们(什么样的设置...
这两种说法之间存在微妙但显着的差异。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_CALL
为EXPECT_CALL
指定的调用提供默认行为。但是如果你写
EXPECT_CALL(mock, Sign(Gt(0), _).WillRepeatedly(Return(1));
EXPECT_CALL(mock, Sign(10, _));
mock.Sign(10, p)
的调用将返回 0。它将与第二个期望相匹配。该期望不指定显式操作,gMock 将为其生成默认操作。该默认操作是返回返回类型的默认值,对于int
为 0。在这种情况下,第一个期望将被完全忽略。
ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));
EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));
正如你所说,这两条线在做完全相同的事情,因此根本没有区别。使用任一方式根据需要设置默认操作。
但是,有一个逻辑上的区别:
ON_CALL(mock, methodX(_)).WillByDefault(Return(0x01));
意味着可能会调用该方法,如果发生这种情况,则每次调用都将返回0x01EXPECT_CALL(mock, methodX(_)).WillRepeatedly(Return(0x01));
表示预期将调用该方法,并且每次调用都将返回0x01
顺便说一下,他们的备忘单中有一个设置默认操作,上面写着:
若要自定义特定方法的默认操作,请使用 ON_CALL():
ON_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.WillByDefault(action);
以下是 gMock 食谱中解释的关于ON_CALL
和EXPECT_CALL
之间最重要差异的"官方"解释。
基本上有两种构造来定义模拟对象的行为:ON_CALL
和EXPECT_CALL
。
区别?
ON_CALL
定义了调用模拟方法时会发生什么,但并不意味着对被调用的方法有任何期望。
EXPECT_CALL
不仅定义了行为,而且还设置了一个期望,即必须使用给定的参数在给定的次数内(以及指定顺序时也按给定的顺序)调用该方法。
既然EXPECT_CALL
做得更多,那不是比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
定义了默认行为设置也是如此。
请参阅此处 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不仅定义了行为,而且还设置了一个期望值,即该方法将在给定的次数内使用给定的参数调用(并且在指定顺序时也按给定的顺序调用)。
我很困惑,没有答案提到最重要的术语:无趣的电话。
EXPECT_CALL信号,表示函数调用是相关/有趣的。如果预期的函数调用与您的规范(调用次数、参数等)不匹配,则这是一个失败的期望,会导致测试用例失败。
如果使用ON_CALL而没有对相应的功能进行任何进一步的EXPECT_CALL,那么这表明该函数是"无趣的",并且进一步的行为在很大程度上取决于我们使用的模拟类型(strict/naggy/nice),范围从忽略调用到测试用例失败。
将EXPECT_CALL用于测试目的所必需的内容,使用 ON_CALL 指定浏览待测试代码所需的操作,如果没有特别要求,则通过跳过EXPECT_CALL来避免过度规范以及ON_CALL不相关的函数(并使用 GMock 定义的默认行为)。
- "error: no matching function for call to"构造函数错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 调用专用模板时出错"no matching function for call to [...]"
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 数据成员SFINAE的C++17测试:gcc vs clang
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 正在VS调试器中监视映射条目
- Confusion: decltype vs std::function
- 将IBM Rhapsody模型集成到VS 2019中
- VS Code "command":"make"与终端窗口中的命令行"make"不同
- 使用VS Code和CMake Tools运行自定义命令
- 修改 VS Code 中的默认C++代码段
- 如何使用c++在VS 2019上运行SQL查询
- vs 2015 constexpr变量不恒定,但与2019相比还好吗
- "no matching function for call to 'Vector::Vector'"错误
- 完美前进使用 std::forward vs RefRefCast
- C# vs C++ DLL call
- asm inline vs 2015 with call RegCreateKeyEx
- ODBC call SQLFetch vs SQLFetchScroll