谷歌模拟 - 我可以在同一个模拟对象上多次调用 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 吗? 的相关文章

  • 在派生虚函数中强制执行正确的参数类型

    我发现很难非常简洁地描述这个问题 所以我附上了演示程序的代码 总的想法是 我们需要一组派生类 它们被迫从基类实现一些抽象 Foo 函数 每个派生的 Foo 调用都必须接受不同的参数作为输入 但所有参数也应该从 BaseInput 类派生 到
  • 如何扩展 C# 内置类型,例如 String?

    我需要Trim a String 但我想删除字符串本身内所有重复的空格 而不仅仅是在其末尾或开头 我可以用这样的方法来做到这一点 public static string ConvertWhitespacesToSingleSpaces s
  • 调用 std::adjacent_difference() 时的隐式转换

    我想获得相邻之间距离的向量points在向量中 struct Point double x y z vector
  • VSTO 功能区库,看起来像 Word 2010 中的样式选择器

    我正在用 C 编写功能区 COM 加载项 并尝试在新选项卡上创建可用模板文件库 是否可以将图库设置为像 Word ie 中主页选项卡上的样式选择器图库一样打开 显示图库中的所有文件名 MS 不允许其他人使用带内画廊在 Outlook 200
  • 使用蒙特卡罗方法计算 PI 给出的答案不精确

    我正在尝试使用蒙特卡罗方法计算 PI 无论 MAXLEN 有多大 我的代码给出的结果都是 3 000 经过多次调试 我无法明白我做错了什么 include
  • 查询 LDAP 以查找过去 24 小时内创建的所有计算机对象

    我正在尝试使用 LDAP 查询返回过去 24 小时内创建的所有计算机对象 我的代码目前如下所示 Declare new DirectoryEntry and DirectorySearcher DirectoryEntry domainRo
  • 如何从我的应用程序在用户默认浏览器中启动 URL?

    如何在桌面应用程序中添加一个按钮 使用户的默认浏览器启动并显示应用程序逻辑提供的 URL Process Start http www google com
  • 如何在C#中隐藏文件?

    我想在c 中隐藏一个文件 我知道文件路径并且可以创建 FileInfo 对象 我怎样才能隐藏它 之前接受的答案 File SetAttributes path FileAttributes Hidden 将导致它可能丢失某些其他属性 因此您
  • 嵌入式Python,导入数学错误

    首先我使用的是 Mac OSX 10 12 6 我想在我的 C 应用程序中嵌入 python 环境 我把 github python 项目放在https github com python cpython https github com
  • 当我将鼠标悬停在组合框项目上时引发事件

    当我将鼠标悬停在组合框项目上时 我无法找到要触发的事件 我正在使用 Windows 窗体来构建应用程序 我发现WPF有类似的东西 当我将鼠标悬停在组合框项目上时如何更改标签文本 https stackoverflow com questio
  • pthread 线程状态

    是否有一种机制可以用来判断 pthread 线程当前是否正在运行或已退出 如果线程尚未退出 pthread join 是否有一种方法能够在特定时间段后超时 如果您仅针对 Linux 请使用http www kernel org doc ma
  • 在 C# 中捕获异常

    我有一个简单的添加按钮 ADD Click 代码是 protected void Add Click object sender EventArgs e string strConnectionString ConfigurationMan
  • 错误:扩展器控件可能无法在 PreRender 之前注册

    我正在尝试将 Ajax 控件添加到我的 aspx 页面 我刚刚添加了
  • OpenCV 图像处理——C++、C、Python

    我正在考虑在一个项目中尝试 OpenCV 并注意到它有 C C 和 Python 我正在尝试确定是否应该使用 C C 还是 Python 并且希望使用具有最佳 OpenCV 支持的任何语言 仅从查看各种文档的索引页来看 C 绑定可能比其他绑
  • 无堆栈协程与堆栈协程有何不同?

    背景 我问这个问题是因为我目前有一个具有许多 数百到数千 线程的应用程序 这些线程中的大多数在很大一部分时间内处于空闲状态 等待将工作项放入队列中 当工作项可用时 它会通过调用一些任意复杂的现有代码来处理 在某些操作系统配置上 应用程序会遇
  • 基于路由参数的子容器注册

    我们有一个多租户 ASP NET MVC 应用程序 为多个客户端托管预订引擎 这些客户端中的每一个都有多个可以影响 Unity 容器配置的包 我们为每个请求创建一个子容器 并根据通过路由传递的客户端和包参数注册不同的接口实现 目前 我们正在
  • ncurses 和curses - 编译器未定义的引用

    好吧 我最初一直在尝试使用一些据称仅适用于 Windows 的标头 我的错 但我已经使用curses h 重现了我需要的内容 但是我仍然收到完全相同的错误 usr bin gmake f nbproject Makefile Debug m
  • .NET 中是否有任何集合可以防止空条目?

    我特别考虑的是履行一套合同的集合 但我认为这个问题可以适用于任何类型 NET 框架中是否存在可以防止空条目的集合 我想要的具体行为是这样的 var set new HashSet bool added set Add null Consol
  • 在头文件 (.h) 中声明构造函数然后在类文件 (.cpp) 中定义 C++ 的语法 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果有人可以解决这个问题 我将不胜感
  • Windows 窗体应用程序中异常处理的最佳实践?

    我目前正在编写我的第一个 Windows 窗体应用程序 我现在已经阅读了几本 C 书籍 因此对 C 必须处理异常的语言特性有了相对较好的了解 然而 它们都非常理论化 因此我还没有了解如何将基本概念转化为应用程序中良好的异常处理模型 有人愿意

随机推荐