重要说明:Google Mock要求在调用模拟函数之前设置,否则行为未定义。特别是,您不能交错EXPECT_CALL()和调用模拟函数。
有没有人知道此限制背后的任何细节?我有一些单元测试肯定违反了这个规则,但似乎运行正常。
答案 0 :(得分:3)
我必须不同意@Marko Popovic's assessment,并相信他所做的是未定义的行为,该行为会起作用。 我亲眼看到他在做什么,打了个电话,看起来还不错。但我认为这是不确定的行为。
尽管如此,我需要Google的明确说明,所以我在这里打开了这个问题:https://github.com/google/googletest/issues/2828。请加快投票以引起关注,因为我希望Googletest小组自己对此予以澄清。
更新:Google has responded,并声明@Marko Popovic的答案取决于未定义的行为。但是,这是一个非常常见的陷阱,因为正如Marko所指出的,并且正如我所看到的,它确实有效(至少在大多数情况下)。问题在于它依赖于未定义的gmock行为。
行为未定义的问题是它经常运行,但在技术上不正确,可能有错误,可能导致不稳定的测试,并且在将来更新gmock时可能因未知原因而中断在将来。简而言之:未定义的行为不能适应未来,也不能跨平台。这也可能导致竞争状况,或者并非始终有效。因此,请不要这样做。听听Google。他们声明以下内容的声明实际上是正确的:
尤其是,您不得交错
EXPECT_CALL()
和对模拟函数(https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests)的调用
回到我的原始答案:
在我的另一个回答中,我谈到了如何正确使用多个EXPECT_CALL()
的 lot ,我说交织还不行:google mock - can I call EXPECT_CALL multiple times on same mock object?
[QUOTE FROM MY OWN WRITING START]
问题3:我可以调用EXPECT_CALL
来设置模拟方法的某些期望值,调用模拟方法,然后再次调用该方法的EXPECT_CALL
来更改期望值,然后调用再次使用模拟方法?
OP甚至没有明确地问这个问题,但我找到此页面的唯一原因是因为我一直在寻找这个答案很长时间,却找不到。我在Google上的搜索是“ [gmock多个Expect_call] [10]”。因此,其他提出此问题的人也将落在此页面上,并且需要最终的答案。
A:不,您不能这样做!根据Google的说法,尽管它可能看起来似乎可以在测试中起作用,但它会产生未定义的行为。参见上面的一般规则#2!
“ 重要说明::gMock要求在调用模拟功能之前设置期望,否则行为未定义。特别是,您不得交错
EXPECT_CALL()
和对模拟函数的调用“(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(...);
}
答案 1 :(得分:1)
正如文档所述,重要的是在调用方法之前设置期望。但是,这并不意味着
交错EXPECT_CALL
和模拟方法的调用是不可能的。例如,假设我们有以下模拟
类
class MyMock : public bravo::IRealClass
{
public:
...
MOCK_METHOD1(myMethod, bool(int));
...
}
现在,假设对方法testMethod
的调用只调用myMethod
一次,您可以在测试中编写类似的内容:
TEST(FooTest, testCaseName)
{
MyMock myMockObj;
...
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
testMethod();
ASSERT_THAT(...);
}
这没关系,因为没有设定期望就没有myMethod
的电话。但是,如果你要切换第二个位置
上面的伪代码中的EXPECT_CALL
和testMethod
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);
testMethod();
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
ASSERT_THAT(...);
您正在进入未定义行为的领域。与未定义行为的情况一样,它可能不会崩溃 在某些情况下。但是,如果您在代码中确实有类似的内容,则必须更改它。