本文介绍了谷歌模拟 - 我可以在同一个模拟对象上多次调用 EXPECT_CALL 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在同一个 TEST_F 中的同一个模拟对象上两次调用 EXPECT_CALL ...会发生什么?

If I call EXPECT_CALL twice on the same mock object in the same TEST_F . . . what happens?

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

Are the expectations appended to the mock object or does the second call erase the effects of the first call?

我发现了之后子句似乎暗示允许多次调用同一个模拟+ EXPECT_CALL.

I found The After Clause which appears to imply that multiple calls to same mock + EXPECT_CALL are allowed.

推荐答案

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

Yes, you can call EXPECT_CALL on the same mock object multiple times. As long as you assure that all EXPECT_CALL were called before the mocked methods were actually used. Otherwise your test will rely on undefined behavior. From ForDummies:

重要说明:gMock 要求在调用模拟函数之前设置期望值,否则行为未定义.特别是,您不能将 EXPECT_CALL() 和对模拟函数的调用交织在一起.

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

How multiple calls will be handled? The documentation is really straightforward. From ForDummies:

默认情况下,当调用一个模拟方法时,Google Mock 会搜索以相反的顺序定义期望,并在出现时停止找到与参数匹配的主动期望(你可以认为将其视为新规则覆盖旧规则.").

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

Let's consider what this means for the gMock user, by checking some examples. I assume that we have a file with following header:

#include <gmock/gmock.h>

using namespace ::testing;

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

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

The simplest example of passing test that calls EXPECT_CALL multiple times:

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#1exp#2 不匹配,所以 exp#1 被尝试并匹配.
  • call#2exp#2 匹配.
  • call#1 does not match with exp#2 so exp#1 is tried and matches.
  • call#2 matches with exp#2.

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

Both calls matched exactly once, thus they are considered satisfied and the test passes.

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

The tricky part starts when multiple EXPECT_CALL are able to match the call. Let's consider the following example:

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 再次没有机会被匹配.
    • The call#1 matches the exp#2. gMock stops at first matched expectation, it won't check the exp#1 at all.
    • The call#2 matches the exp#2. Again the exp#1 does not have chance to be matched.
    • 结果测试失败,因为 exp#2 被匹配两次而不是一次,并且 exp#1 根本不匹配.测试输出中打印的所有内容:

      As a result the test fails as the exp#2 gets matched twice instead of once and exp#1 is not matched at all. All that is printed in the test output:

      /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
      

      此外,重要的是,添加新的预期不会禁用或删除旧的.他们仍然可以通过您的测试!

      Also, it is important, that adding new expectancy won't disable or remove old ones. They are still able to fail your test!

      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 匹配的次数不够多.

      Both call#1 and call#2 matches the exp#2. As a result the exp#2 is satisfied, but the test will fail as exp#1 was not matched enough times.

      如果出于某种原因,您需要编写像 TheSameArgumentsGoingToFail 这样的测试,您可以使用多种技术来防止 exp#2 再次匹配.请参阅文档 InSequence 用法RetiresOnSaturation:

      If for some reason, you need to write a test like TheSameArgumentsGoingToFail, you can use a number of techniques to prevent exp#2 from matching second time. Please refer to the documentation InSequence usage, 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
      }
      

      这篇关于谷歌模拟 - 我可以在同一个模拟对象上多次调用 EXPECT_CALL 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 09:19
查看更多