交错EXPECT_CALL()和调用mock函数

时间:2016-10-17 14:35:27

标签: c++ unit-testing googletest googlemock expectations

Google Mock documentation说:

  

重要说明:Google Mock要求在调用模拟函数之前设置,否则行为未定义。特别是,您不能交错EXPECT_CALL()和调用模拟函数。

有没有人知道此限制背后的任何细节?我有一些单元测试肯定违反了这个规则,但似乎运行正常。

2 个答案:

答案 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. @Marko Popovic's assessment
  2. 我要求澄清以下问题的Googletest问题:https://github.com/google/googletest/issues/2828
  3. [我自己的答案] google mock - can I call EXPECT_CALL multiple times on same mock object?

答案 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_CALLtestMethod

EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(true));
testMethod();
ASSERT_THAT(...);

testMethod();
EXPECT_CALL(myMockObj, myMethod(_)).WillOnce(Return(false));
ASSERT_THAT(...);

您正在进入未定义行为的领域。与未定义行为的情况一样,它可能不会崩溃 在某些情况下。但是,如果您在代码中确实有类似的内容,则必须更改它。