google mock - 我可以在同一个模拟对象上多次调用 EXPECT_CALL 吗?

新手上路,请多包涵

如果我在同一个模拟对象上调用 EXPECT_CALL 两次 TEST_F 。 . .怎么了?

是附加到模拟对象的期望还是第二次调用消除了第一次调用的影响?

我发现 After Clause 似乎暗示允许多次调用同一个模拟 + EXPECT_CALL。

原文由 Bob 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.9k
1 个回答

是的,您可以在同一个模拟对象上多次调用 EXPECT_CALL 。只要您确保在实际使用模拟方法之前调用了所有 EXPECT_CALL 。否则,您的测试将依赖于未定义的行为。来自 ForDummies

重要提示:gMock 要求在调用模拟函数之前设置期望,否则行为未定义。特别是,您不能将 EXPECT_CALL() 和对模拟函数的调用交错。

如何处理多个呼叫?文档非常简单。来自 ForDummies

默认情况下,当调用模拟方法时,Google Mock 将按照定义的相反顺序搜索期望,并在找到与参数匹配的活动期望时停止(您可以将其视为“新规则覆盖旧规则。 ”)。

让我们通过检查一些示例来考虑这对 gMock 用户意味着什么。我假设我们有一个带有以下标题的文件:

 #include <gmock/gmock.h>

using namespace ::testing;

struct SomeMock
{
    MOCK_CONST_METHOD1(foo, void(int));
};

通过多次调用 EXPECT_CALL 的测试的最简单示例:

 TEST(Examples, DifferentArgumentsGoingToBeOk)
{
    SomeMock mock;

    EXPECT_CALL(mock, foo(4)).Times(1); // exp#1
    EXPECT_CALL(mock, foo(5)).Times(1); // exp#2

    mock.foo(4); // call#1
    mock.foo(5); // call#2
}

测试直观地工作:

  • call#1 不匹配 exp#2 所以 exp#1 被尝试和匹配。
  • call#2exp#2 匹配。

两个调用只匹配一次,因此它们被认为是满意的并且测试通过了。

当多个 EXPECT_CALL 能够匹配调用时,棘手的部分就开始了。让我们考虑以下示例:

 TEST(Examples, TheSameArgumentsGoingToFail) // Test fails!
{
    SomeMock mock;

    EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
    EXPECT_CALL(mock, foo(4)).Times(1); //exp#2

    mock.foo(4); // call#1
    mock.foo(4); // call#2
}

  • call#1 匹配 exp#2 。 gMock 在第一次匹配预期时停止,它根本不会检查 exp#1
  • call#2 匹配 exp#2 。再次, exp#1 没有机会匹配。

结果测试失败,因为 exp#2 匹配了两次而不是一次,并且 exp#1 根本不匹配。测试输出中打印的所有内容:

 /tmp/so/main.cpp:26: Failure // exp#2
Mock function called more times than expected - returning directly.
    Function call: foo(4)
         Expected: to be called once
           Actual: called twice - over-saturated and active
/tmp/so/main.cpp:25: Failure // exp#1
Actual function call count doesn't match EXPECT_CALL(mock, foo(4))...
         Expected: to be called once
           Actual: never called - unsatisfied and active

此外,重要的是,添加新的期望值不会禁用或删除旧的期望值。他们仍然能够通过您的测试!

 TEST(Examples, NewExpectCallDoesNotEraseThePreviousOne) // Test fails!
{
    SomeMock mock;

    EXPECT_CALL(mock, foo(4)).Times(1); // exp#1
    EXPECT_CALL(mock, foo(4)).Times(2); // exp#2

    mock.foo(4); // call#1
    mock.foo(4); // call#2
}

call#1call#2 都匹配 exp#2 。结果 exp#2 得到满足,但测试将失败,因为 exp#1 没有足够的匹配次数。

如果出于某种原因,您需要编写类似 TheSameArgumentsGoingToFail 的测试,您可以使用多种技术来防止 exp#2 第二次匹配。请参考文档 InSequence 用法RetiresOnSaturation

 TEST(Examples, InSequenceExample)
{
    SomeMock mock;

    Sequence seq;

    EXPECT_CALL(mock, foo(4)).Times(1).InSequence(seq); //exp#1
    EXPECT_CALL(mock, foo(4)).Times(1).InSequence(seq); //exp#2

    mock.foo(4); // call#1
    mock.foo(4); // call#2
}

TEST(Examples, InSequenceExampleSecondApproach)
{
    SomeMock mock;

    InSequence seq;

    EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
    EXPECT_CALL(mock, foo(4)).Times(1); //exp#2

    mock.foo(4); // call#1
    mock.foo(4); // call#2
}

TEST(Examples, RetiresOnSaturationExample)
{
    SomeMock mock;

    EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
    EXPECT_CALL(mock, foo(4)).Times(1).RetiresOnSaturation(); //exp#2

    mock.foo(4); // call#1
    mock.foo(4); // call#2
}

TEST(Examples, AfterExample)
{
    SomeMock mock;

    auto& exp1 = EXPECT_CALL(mock, foo(4)).Times(1); //exp#1
    EXPECT_CALL(mock, foo(4)).Times(1).After(exp1); //exp#2

    mock.foo(4); // call#1
    mock.foo(4); // call#2
}

原文由 luantkow 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题