繁体   English   中英

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

[英]google mock - can I call EXPECT_CALL multiple times on same mock object?

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

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

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

是的,您可以在同一个模拟对象上多次调用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#1exp#2不匹配,因此尝试并匹配exp#1
  • call#2exp#2 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#1exp#2匹配。 gMock 在第一次匹配期望时停止,它根本不会检查exp#1
  • call#2exp#2 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 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
}

可以在此处的 Google 的 gtest 文档中找到此答案的链接作为我的 GitHub 存储库中的文章googletest/docs/community_created_documentation.md


以下所有代码均使用 2019 年 10 月 3 日发布的 Googletest/Googlemock v1.10.0进行了测试。

如果您想为自己运行测试,但没有在您的系统上设置 googletest 或 googlemock,这里是我创建的一个准系统项目,用于在 Ubuntu 上快速启动和运行。 去克隆它并自己玩。 它也可以作为帮助您在 Mac 或 Windows 上运行的起点。

这是一个非常重要的问题,所以我觉得有必要对它进行破解。

细微差别:

首先让我说 Google Mock (gmock) 是有细微差别的。 这意味着有很多微妙之处需要理解,这很困难。 甚至文档也有点分散,您需要仔细阅读和研究所有内容才能真正掌握其中的一些甚至大部分细微差别,因为它们在每个文档中都不能很好地重复某些重要点. 所以,这里是所有官方文档:如果你这样做是为了工作,请告诉你的主管你将留出几天时间仔细阅读 gtest 和 gmock 文档并练习示例以牢牢掌握它.

文档:

在阅读和研究以下文档时,将每个文档另存为(打印到)PDF,然后在 Windows、Mac 或 Linux 上免费使用Foxit Reader来编辑、记笔记、突出显示或下划线 PDF去。 这样,您就可以记录需要记住的最重要的事情。 在此处此处查看我的*_GS_edit.pdf PDF,了解我在学习 Google Test 和 Google Mock 时所做的笔记和标记 PDF 的示例。

谷歌官方文档:

  1. gtest:都在这个文件夹中: https ://github.com/google/googletest/tree/master/googletest/docs。 要研究的关键文件可能是:
    1. 底漆
    2. 常问问题
    3. 示例(查看并仔细研究至少前 3 个示例的源代码)
    4. 先进的
  2. gmock:都在这个文件夹中: https ://github.com/google/googletest/tree/master/googlemock/docs。 要研究的关键文件可能是:
    1. 假人用
    2. 烹饪书
    3. 备忘单- 这是所有文档中最好的一站式商店或“gmock 规则摘要”,但缺少一些您将在(且仅在)“傻瓜”手册中明确说明的内容除了这个文档还需要。
    4. 常问问题
    5. 对于傻瓜<--是的,再次! 在完成并尝试编写一堆测试和模拟之后,然后再回来重新阅读此文档! 在首先将 gtest 和 gmock 原则付诸实践之后,第二次会更有意义。

一般要记住的一些微妙规则:

  1. “请记住,测试顺序是未定义的,因此您的代码不能依赖于之前或之后的测试”( https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#sharing -resources-between-tests-in-the-same-test-suite )。
  2. 重要提示: gMock 要求在调用模拟函数之前设置期望值,否则行为未定义。特别是,您不能将EXPECT_CALL()和对模拟函数的调用交错”( https://github.com /google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests

答案:

问题 1:“如果我在同一个TEST_F中的同一个模拟对象上调用EXPECT_CALL两次……会发生什么?”

答:首先,在这种情况下,您使用的是TEST()宏还是TEST_F()宏都没有区别。 TEST()宏简单地扩展为从::testing::Test类公开继承的类,而TEST_F()宏简单地扩展为从测试夹具类继承的类( TEST_F()的第一个参数) ,它必须从::testing::Test类公开继承。

可以在同一个mock对象(mock类)上调用EXPECT_CALL ,从一般到具体,如下:

同一个 mock 对象上多个EXPECT_CALL的 3 条规则:
从最通用的--> 最具体的(又名:“外部”-->“内部”范围)。

  1. 每个模拟方法至少可以有一个EXPECT_CALL一个模拟类可以有许多模拟方法,因此每个方法可能有一个或多个EXPECT_CALL配置与该方法的预期交互。 因此,模拟类的每个方法至少可以有一个EXPECT_CALL

  2. 在单个模拟方法上,每个匹配器签名不应超过一个EXPECT_CALL在下面的规则 3 中了解更多信息)。 每个模拟方法都有许多不同的参数可以传入,因此每个匹配器签名最多可以有一个EXPECT_CALL (可能的参数值或值组合,在多个输入参数的情况下)。 这意味着每个模拟方法可能有数千甚至数百万甚至数十亿有效且唯一的EXPECT_CALL附加到它,每个都匹配一组不同的“匹配器”或模拟方法的输入参数。 例如,这是完全有效的:

     // Each `EXPECT_CALL()` in this example has a different and // unique "matcher" signature, so every `EXPECT_CALL()` will // take effect for its matching parameter signature when // `myMockMethod()` is called. // v--matchers EXPECT_CALL(myMockClass, myMockMethod(1)); EXPECT_CALL(myMockClass, myMockMethod(2)); EXPECT_CALL(myMockClass, myMockMethod(3)); EXPECT_CALL(myMockClass, myMockMethod(4)); EXPECT_CALL(myMockClass, myMockMethod(5)); ... EXPECT_CALL(myMockClass, myMockMethod(1000));

    特别是,上面的每个EXPECT_CALL都指定对具有匹配签名的myMockMethod()的调用必须恰好发生 1 次 这是因为在这种情况下, 基数规则规定了隐含的.Times(1)存在于每个EXPECT_CALL上,即使您没有看到它被写入。

    要指定您希望给定的EXPECT_CALL处理给定参数的任何输入值,请使用::testing::_匹配器,如下所示:

     using ::testing::_; EXPECT_CALL(myMockClass, myMockMethod(_));
  3. 在同一个模拟方法上没有具有相同匹配器签名的重复EXPECT_CALL s EXPECT_CALL在同一个模拟方法上具有重叠/覆盖(但不重复)匹配器签名的多个 EXPECT_CALL 是可以的:如果您将多个EXPECT_CALL附加到相同的匹配值,只有最后一组会有任何效果。 例如,请参见此处此处此处 这意味着如果您有两个或多个EXPECT_CALL具有重复的匹配器签名(传递给模拟方法的相同参数),那么只有最后一个会得到任何呼叫。

    因此,您的测试将始终失败,除非在异常情况下,除最后一个之外的所有EXPECT_CALL都具有.Times(0)值,指定它们永远不会被调用,因为确实是这种情况:最后一个EXPECT_CALL将匹配所有这些匹配器的调用以及上面所有重复的EXPECT_CALL没有匹配的调用! 这是一个测试的例子,它总是会因为这种行为而失败。 这是@luantkow在此处的回答中关注的主要行为。

     using ::testing::_; // Notice they all have the same mock method parameter "matchers" // here, making only the last `EXPECT_CALL()` with this matcher // signature actually match and get called. Therefore, THIS TEST // WILL ***ALWAYS FAIL***, since EXPECT_CALL #1 expects to get // called 1 time but is NEVER called, #2 through #1006, inclusive, // all expect to get called 2 times each but all of them are NEVER // called, etc.! Only #1007 is ever called, since it is last and // therefore always matches first. // v--matchers EXPECT_CALL(myMockClass, myMockMethod(_)).Times(1); // EXPECT_CALL #1 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(2); // EXPECT_CALL #2 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(2); // EXPECT_CALL #3 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(2); // EXPECT_CALL #4 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(2); // EXPECT_CALL #5 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(2); // EXPECT_CALL #6 // ... duplicate the line just above 1000 more times here EXPECT_CALL(myMockClass, myMockMethod(_)).Times(3); // EXPECT_CALL #1007

    然而,这个奇怪的例外使测试有效,只需将所有重复的EXPECT_CALL s(除了最后一个)设置为.Times(0)基数设置:

     using ::testing::_; // Notice they all have the same mock method parameter "matchers" // here, making only the last `EXPECT_CALL()` with this matcher // signature actually match and get called. However, since all previous // `EXCEPT_CALL` duplicates are set to `.Times(0)`, this test is valid // and can pass. // v--matchers EXPECT_CALL(myMockClass, myMockMethod(_)).Times(0); // EXPECT_CALL #1 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(0); // EXPECT_CALL #2 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(0); // EXPECT_CALL #3 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(0); // EXPECT_CALL #4 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(0); // EXPECT_CALL #5 EXPECT_CALL(myMockClass, myMockMethod(_)).Times(0); // EXPECT_CALL #6 // ... duplicate the line just above 1000 more times here EXPECT_CALL(myMockClass, myMockMethod(_)).Times(3); // EXPECT_CALL #1007

    在这里,只有EXPECT_CALL #1007 (最后一个EXPECT_CALL )将匹配对myMockMethod()的调用,并且Times(3)将生效。 由于在此之上的所有重复EXPECT_CALL都将永远不会匹配和获取调用,因为它们永远不会到达,对于给定匹配器的重复EXPECT_CALL的测试对于所有非.Times(0)以外的任何.Times()值总是会失败-last-place 重复EXPECT_CALL s。

    这种使后面的匹配器能够覆盖前面的匹配器的效果是有意的,也是 Googlemock 设计的一部分,因为它允许您根据传递给模拟方法的值创建一种非常有用的预期调用层次结构,如下所示:

     using ::testing::_; // Most general matchers first (_ matches any input value) EXPECT_CALL(myMockClass, myMockMethod(_)).Times(1); // More specific matchers next, to override the more general matcher // above if they match EXPECT_CALL(myMockClass, myMockMethod(7)).Times(2); EXPECT_CALL(myMockClass, myMockMethod(5)).Times(4);

    各种谷歌文档说匹配的EXPECT_CALL s 是按相反的顺序搜索的,从下到上 所以,如果myMockMethod(8)被调用,它将根据这个方法的最后一个EXPECT_CALL进行检查,该方法正在寻找myMockMethod(5) 这不匹配,所以它上升一个并检查myMockMethod(7) 这不匹配,所以它上升一个并检查myMockMethod(_) 这匹配! 因此,它算作Times(1)基值授权的一次调用。

    所以,你上面定义的是:我们期望myMockMethod(5)被调用 4 次, myMockMethod(7)被调用 2 次, myMockMethod(anything_other_than_5_or_7)被调用 1 次。 有关此主题的更多阅读,请参阅我的其他答案: google mock - 如何说“函数必须使用某个参数调用一次,但可以使用不同的参数多次调用”? .

关键摘要:关于“我可以在同一个模拟对象多次调用EXPECT_CALL吗?”这个问题要记住的EXPECT_CALL是:如果匹配器(参数指定为传递给模拟方法)对于每个EXPECT_CALL都是不同的。 也就是说,当然,除非您在除最后一个重复的EXPECT_CALL的所有内容上设置.Times(0) ,这会使它们无用,因此请记住不要使用相同的匹配器重复EXPECT_CALL

这完全回答了这个问题。


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

上面的描述也回答了这个问题。 本质上, EXPECT_CALL期望不会覆盖它们之前的任何EXPECT_CALL的效果,除非匹配器(指定要传递给模拟方法的值)相同或重叠,在这种情况下,只有最后一个EXPECT_CALL会被调用,因为它总是在匹配序列中的其他之前到达。 因此,不要在给定的模拟方法上使用具有相同匹配器的重复EXPECT_CALL ,否则您可能会无意中强制测试始终失败,因为上述EXPECT_CALL永远不会被调用。 这在上面的问题 1 中有详细讨论。

同样,有关此主题的更多阅读,请阅读上文,并在此处查看我的其他答案: google mock - 如何说“函数必须使用某个参数调用一次,但可以使用不同的参数多次调用”? .


问题3:我可以调用EXPECT_CALL对mock 方法设置一些期望,调用mock 方法,然后在该方法上再次调用EXPECT_CALL以改变期望,然后再次调用mock 方法吗?

OP 甚至没有明确提出这个问题,但我找到这个页面的唯一原因是因为我花了好几个小时搜索这个答案却找不到。 我的谷歌搜索是“ gmock multiple expect_call ”。 因此,其他提出此问题的人也将落在此页面上,需要一个确凿的答案。

答:不,你不能这样做! 尽管它似乎在测试中起作用,但根据 Google 的说法,它会产生未定义的行为 请参阅上面的一般规则 #2!

重要提示: gMock 要求在调用模拟函数之前设置期望值,否则行为未定义。特别是,您不能将EXPECT_CALL()和对模拟函数的调用交错”( https://github.com /google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests

另请参阅我的答案:交错EXPECT_CALL()和调用模拟函数是未定义的行为

因此,这是不允许的!:

// EXAMPLE OF A BAD TEST THAT MAY SEEM TO WORK BUT IS RELYING ON *UNDEFINED* BEHAVIOR!
// The goal is to ensure that `myMockMethod()` is only called 2x the first time by 
// `myOtherFunc()`, 3x the second time, and 0x the last time.

// Google states: "**Important note:** gMock requires expectations to be set 
// **before** the mock functions are called, otherwise the behavior is **undefined**. 
// In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions"
// (https://github.com/google/googletest/blob/master/googlemock/docs/for_dummies.md#using-mocks-in-tests)

using ::testing::_;

TEST_F(MyTestFixture, MyCustomTest) 
{
    // `myMockMethod()` should be called only 2x here by `myOtherFunc()`,
    // despite calling `myOtherFunc()` repeatedly
    EXPECT_CALL(MyMockClass, myMockMethod(_, _))
        .Times(2);
    for (int i = 0; i < 10; i++)
    {
        myOtherFunc();
    }

    // UNDEFINED BEHAVIOR BEGINS HERE: you can't interleave calls to `EXPECT_CALL` with 
    // calls to the mocked functions (in this case: `myMockMethod()`,
    // which is called by `myOtherFunc()`).

    // THEN `myMockMethod()` should be called 3x here by `myOtherFunc()`
    EXPECT_CALL(MyMockClass, myMockMethod(_, _))
        .Times(3);
    for (int i = 0; i < 10; i++)
    {
        myOtherFunc();
    }

    // LAST, `myMockMethod()` should be called 0x here by `myOtherFunc()`
    EXPECT_CALL(MyMockClass, myMockMethod(_, _))
        .Times(0);
    for (int i = 0; i < 10; i++)
    {
        myOtherFunc();
    }
}

那么,这里的有效解决方案是什么? 好吧,如果您可以将此测试分成 3 个不同的独立测试,那就这样做吧! 但是,如果这 3 个测试以您无法将它们分开的方式相互关联怎么办? 示例:您正在尝试测试一个节流函数,该函数将打印输出限制为每秒一次,例如,即使您尝试打印的频率高于每秒一次。 好吧,在这种情况下,有一些解决方法。

首先,让我们回顾一下:根据Google Mock Cheat Sheet ,以下是配置EXPECT_CALL()的方法:

EXPECT_CALL(mock-object, method (matchers)?)
     .With(multi-argument-matcher)  ?
     .Times(cardinality)            ?
     .InSequence(sequences)         *
     .After(expectations)           *
     .WillOnce(action)              *
     .WillRepeatedly(action)        ?
     .RetiresOnSaturation();        ?

对于上述每一项, ? 表示最多可以使用一次,而*表示可以使用任意次数。

我们需要将.WillRepeatedly(action) action产生副作用调用函数、仿函数或 lambda作为动作的动作一起使用。

这里有一些变通方法可以安全、正确地执行上述具有未定义行为的测试。 如果你想先看看最好的方法,直接跳到下面的#3:

  1. 使用Assign(&variable, value) 在这种特殊情况下,这有点 hacky,但它确实可以正常工作。 对于您可能拥有的更简单的测试用例,这可能是满足您需要的完美方式。 这是一个可行的解决方案:

    旁注:我在尝试运行 gmock 测试时得到的错误输出说:

    .Times()不能出现在.InSequence().WillOnce().WillRepeatedly().RetiresOnSaturation()之后,

    ...所以事实证明我们不需要(甚至不允许)在这里指定.Times(::testing::AnyNumber()) 相反,gmock 会根据这些基数规则自动计算出来,因为我们使用的是.WillRepeatedly()

    如果您省略Times() ,gMock 将为您推断基数。 规则很容易记住:

    • 如果WillOnce WillOnce()WillRepeatedly()都不在EXPECT_CALL()中,则推断的基数是Times(1)
    • 如果有n 个WillOnce()没有WillRepeatedly() ,其中n >= 1,则基数为Times(n)
    • 如果有n 个WillOnce()一个WillRepeatedly() ,其中n >= 0,则基数为Times(AtLeast(n))

    这种技术实际上已经过测试并证明可以在真实代码上工作:

     using ::testing::_; using ::testing::Assign; TEST_F(MyTestFixture, MyCustomTest) { bool myMockMethodWasCalled = false; EXPECT_CALL(MyMockClass, myMockMethod(_, _)) // Set `myMockMethodWasCalled` to true every time `myMockMethod()` is called with // *any* input parameters! .WillRepeatedly(Assign(&myMockMethodWasCalled, true)); // Do any necessary setup here for the 1st sub-test // Test that `myMockMethod()` is called only 2x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly for (int i = 0; i < 10; i++) { myOtherFunc(); if (i < 2) { EXPECT_TRUE(myMockMethodWasCalled); myMockMethodWasCalled = false; // reset EXPECT_FALSE(myMockMethodWasCalled); // ensure reset works (sanity check) } else { EXPECT_FALSE(myMockMethodWasCalled); } } // Do any necessary setup here for the 2nd sub-test // Test that `myMockMethod()` is called only 3x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly for (int i = 0; i < 10; i++) { myOtherFunc(); if (i < 3) { EXPECT_TRUE(myMockMethodWasCalled); myMockMethodWasCalled = false; // reset EXPECT_FALSE(myMockMethodWasCalled); // ensure reset works (sanity check) } else { EXPECT_FALSE(myMockMethodWasCalled); } } // Do any necessary setup here for the 3rd sub-test // Test that `myMockMethod()` is called 0x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly for (int i = 0; i < 10; i++) { myOtherFunc(); EXPECT_FALSE(myMockMethodWasCalled); } }
  2. InvokeWithoutArgs(f)与全局计数器变量和全局计数器函数一起使用。 这很好用,并且比以前的方法更容易使用和更通用! 请注意,如果您愿意,您也可以将此全局函数和变量迁移到您的测试夹具类中,这样可以稍微清理一下。

    这种技术实际上已经过测试并证明可以在真实代码上工作:

     using ::testing::_; using ::testing::InvokeWithoutArgs; static uint32_t callCounter = 0; static void incrementCallCounter() { callCounter++; } TEST_F(MyTestFixture, MyCustomTest) { EXPECT_CALL(MyMockClass, myMockMethod(_, _)) // Set gmock to increment the global `callCounter` variable every time // `myMockMethod()` is called with *any* input parameters! .WillRepeatedly(InvokeWithoutArgs(incrementCallCounter)); // Do any necessary setup here for the 1st sub-test // Test that `myMockMethod()` is called only 2x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly callCounter = 0; // ensure this is zero BEFORE you start the test! for (int i = 0; i < 10; i++) { myOtherFunc(); } EXPECT_EQ(callCounter, 2); // Do any necessary setup here for the 2nd sub-test // Test that `myMockMethod()` is called only 3x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly callCounter = 0; // ensure this is zero BEFORE you start the test! for (int i = 0; i < 10; i++) { myOtherFunc(); } EXPECT_EQ(callCounter, 3); // Do any necessary setup here for the 1st sub-test // Test that `myMockMethod()` is called 0x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly callCounter = 0; // ensure this is zero BEFORE you start the test! for (int i = 0; i < 10; i++) { myOtherFunc(); } EXPECT_EQ(callCounter, 0); }
  3. [最佳技术] 将InvokeWithoutArgs(f)本地计数器变量和简单的 lambda 函数一起使用! 这很好用,比第一种方法更容易使用和更通用,同时避免了第二种方法的全局变量和额外的全局函数。 这肯定是我最喜欢的处理方式,而且效果非常好。

    这种技术实际上已经过测试并证明可以在真实代码上工作:

     using ::testing::_; using ::testing::InvokeWithoutArgs; TEST_F(MyTestFixture, MyCustomTest) { uint32_t callCounter; EXPECT_CALL(MyMockClass, myMockMethod(_, _)) // Use a lambda function to set gmock to increment `callCounter` every // time `myMockMethod()` is called with *any* input parameters! .WillRepeatedly(InvokeWithoutArgs([&callCounter](){ callCounter++; })); // Do any necessary setup here for the 1st sub-test // Test that `myMockMethod()` is called only 2x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly callCounter = 0; // ensure this is zero BEFORE you start the test! for (int i = 0; i < 10; i++) { myOtherFunc(); } EXPECT_EQ(callCounter, 2); // Do any necessary setup here for the 2nd sub-test // Test that `myMockMethod()` is called only 3x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly callCounter = 0; // ensure this is zero BEFORE you start the test! for (int i = 0; i < 10; i++) { myOtherFunc(); } EXPECT_EQ(callCounter, 3); // Do any necessary setup here for the 1st sub-test // Test that `myMockMethod()` is called 0x here by `myOtherFunc()`, // despite calling `myOtherFunc()` repeatedly callCounter = 0; // ensure this is zero BEFORE you start the test! for (int i = 0; i < 10; i++) { myOtherFunc(); } EXPECT_EQ(callCounter, 0); }

如果您认为应该将整个答案添加为 Gmock 文档中的独立文件(我建议我们这样做),请单击下面的 github 问题链接并对其进行投票。

练习使用 gtest/gmock:

  1. 使用这个项目来练习编写和测试你自己的谷歌测试和谷歌模拟。 这也是如何使用 Google 的Bazel 构建系统启动和运行新项目的一个很好的演示:https ://github.com/ElectricRCAaircraftGuy/eRCaGuy_gtest_practice。

有关的:

  1. 我打开的 GitHub 问题请求将此答案作为独立文档添加到其官方文档中。 如果您同意,请到这里投票赞成这个问题: https ://github.com/google/googletest/issues/2775
  2. google mock - 怎么说“函数必须使用某个参数调用一次,但可以使用不同的参数多次调用”?
  3. Google Mock:对具有不同参数的同一功能的多重期望
  4. google mock - 怎么说“函数必须使用某个参数调用一次,但可以使用不同的参数多次调用”?
  5. 交错 EXPECT_CALL() 和调用模拟函数
    1. 在这里查看我的答案

另一种有用的技术(也显示在 For Dummies 指南中)是只编写一个EXPECT_CALL ,但链接多组指示预期结果的操作。 例如:

SomeMock mock;

EXPECT_CALL(mock, foo(4))
    .WillOnce(Return(16))
    .WillOnce(Return(42))
    .WillOnce(Throw(MyException()));

这需要对具有相同参数的方法进行三次调用,并将在前两次返回指定值,然后在第三次调用时抛出异常。

这通常比使用多个EXPECT_CALLRetiresOnSaturation或其他技术更容易理解。

您也可以将其与 void 方法一起使用; 您只需要使用DoDefault或一些更有趣的操作来代替Return

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM