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

2024-07-04

如果我打电话EXPECT_CALL在同一个模拟对象上两次TEST_F。 。 。会发生什么?

期望是否附加到模拟对象中,或者第二次调用是否消除了第一次调用的效果?

I found 后子句 https://github.com/google/googletest/blob/master/googlemock/docs/cheat_sheet.md#the-after-clause-afterclause这似乎意味着允许多次调用同一模拟+ EXPECT_CALL。


是的,您可以致电EXPECT_CALL多次在同一个模拟对象上。只要你保证一切EXPECT_CALL在实际使用模拟方法之前调用。否则你的测试将依赖于未定义的行为。从对于傻瓜来说 https://github.com/google/googletest/blob/main/docs/gmock_for_dummies.md#using-mocks-in-tests:

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

如何处理多个呼叫?该文档非常简单。从对于傻瓜来说 https://github.com/google/googletest/blob/main/docs/gmock_for_dummies.md#using-multiple-expectations-multiexpectations:

默认情况下,当调用模拟方法时,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 so exp#1经过尝试并匹配。
  • call#2与 匹配exp#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
}
  • The call#1匹配exp#2。 gMock 在第一个匹配的期望处停止,它不会检查exp#1 at all.
  • The 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
}

Both call#1 and call#2匹配exp#2。结果是exp#2满意,但测试将失败,因为exp#1匹配次数不够。

如果由于某种原因,您需要编写类似的测试TheSameArgumentsGoingToFail,您可以使用多种技术来防止exp#2从第二次匹配开始。请参考文档顺序使用 https://github.com/google/googletest/blob/main/docs/gmock_for_dummies.md#ordered-vs-unordered-calls-orderedcalls, 饱和退休 https://github.com/google/googletest/blob/main/docs/gmock_for_dummies.md#all-expectations-are-sticky-unless-said-otherwise-stickyexpectations:

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
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

谷歌模拟 - 我可以在同一个模拟对象上多次调用 EXPECT_CALL 吗? 的相关文章

随机推荐