Jor*_*dan 8 c++ unit-testing expectations googletest googlemock
在谷歌文档模拟说:
重要提示: Google Mock 要求在调用模拟函数之前设置期望值,否则行为是undefined。特别是,您不能将 EXPECT_CALL() 和对模拟函数的调用交织在一起。
有谁知道这个限制背后的任何细节?我有许多单元测试肯定违反了这条规则,但是似乎运行正常。
我不得不不同意@Marko Popovic 的评估,并相信他所做的是碰巧有效的未定义行为。我亲眼看到他在做什么,交错调用,看起来工作得很好。但我认为这是未定义的行为。
尽管如此,我需要谷歌的澄清,所以我在这里打开了这个问题:https : //github.com/google/googletest/issues/2828。请投票以引起注意,因为我希望 Googletest 团队自己澄清这一点。
更新:谷歌已经做出回应,并声明@Marko Popovic 的回答依赖于未定义的行为。然而,这是一个非常常见的陷阱,因为正如 Marko 所指出的,正如我所看到的,它确实有效(至少在大多数时候)。问题在于它依赖于未定义的 gmock 行为。
未定义行为的问题是它经常工作,但在技术上不正确,可能有问题,可能导致不稳定的测试,并且在将来 gmock 更新时可能会因未知原因而中断。简而言之:未定义的行为不是面向未来的,也不是跨平台的。它也可能导致竞争条件或以其他方式不总是有效。因此,不要这样做。听谷歌。他们陈述以下内容的陈述实际上是正确的:
特别是,您不能交错
EXPECT_CALL()s 和对模拟函数的调用(https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests)
回到我原来的回答:
在我的另一个答案中,我谈论了很多关于如何正确使用多个EXPECT_CALL()s 的问题,我声明交错是不行的:google mock - 我可以在同一个模拟对象上多次调用 EXPECT_CALL 吗?
问题3:我可以调用EXPECT_CALL对mock方法设置一些期望,调用mock方法,然后EXPECT_CALL再次调用该方法以更改期望值,然后再次调用mock方法吗?
OP甚至没有明确提出这个问题,但我找到这个页面的唯一原因是因为我搜索了这个答案很多小时却找不到它。我的谷歌搜索是“[gmock multiple expect_call][10]”。因此,其他提出此问题的人也将落在此页面上,需要一个确定性的答案。
答:不,你不能这样做!尽管它在测试中似乎有效,但据 Google 称,它会产生未定义的行为。参见上面的一般规则#2!
"重要说明: gMock 要求在调用模拟函数之前设置期望值,否则行为未定义。特别是,您不能将
EXPECT_CALL()s 和模拟函数的调用交错在一起" ( https://github.com/google/ googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests )
因此,这是不允许的!
[引自我自己的写作结尾]
也许这不是未定义的行为!?我添加的只是Mock::VerifyAndClearExpectations(&myMockObj).
TEST(FooTest, testCaseName)
{
MyMock myMockObj;
...
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);
Mock::VerifyAndClearExpectations(&myMockObj); // <== NOTICE THIS ADDED LINE!
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
testMethod();
ASSERT_THAT(...);
}
Run Code Online (Sandbox Code Playgroud)
正如文档所说,重要的是在调用方法之前设置期望。EXPECT_CALL然而,这并不意味着mock方法不能交错和调用。只是你必须自己明确对mock对象的期望。例如,假设我们有以下模拟类
class MyMock : public bravo::IRealClass
{
public:
...
MOCK_METHOD1(myMethod, bool(int));
...
}
Run Code Online (Sandbox Code Playgroud)
现在,假设对方法的testMethod调用调用myMethod一次,您可以在测试中编写如下内容:
TEST(FooTest, testCaseName)
{
MyMock myMockObj;
...
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);
// Explicitly clear expectations and set new ones.
Mock::VerifyAndClearExpectations(&myMockObj);
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
testMethod();
ASSERT_THAT(...);
}
Run Code Online (Sandbox Code Playgroud)
这很好,因为模拟对象可以可靠地再次重用。但是,如果您忽略明确地清除期望,那么您将进入未定义行为的领域。与未定义行为的情况一样,它可能不会崩溃,甚至在某些情况下可能会起作用,但如果您的代码中有类似的内容,您绝对应该修复它。