GoogleTest中gMock的使用

2023-05-16

      GoogleTest中的gMock是一个库,用于创建mock类并使用它们。
      当你编写原型或测试(prototype or test)时,完全依赖真实对象通常是不可行或不明智的(not feasible or wise)。模拟对象(mock object)实现了与真实对象相同的接口,但是需要你在运行时指定它将如何使用以及它应该做什么.在测试驱动开发(TDD, Test-Driven Development)中经常使用.
      当使用gMock时,首先,使用一些简单的宏来描述要mock的接口,它们将扩展到mock类的实现;接下来,你将创建一些mock对象,并使用直观的语法指定其期望和行为;然后练习(exercise)使用mock对象的code. gMock将在出现任何违反预期的行为时立即捕获(catch)它.

      MOCK_METHOD宏语法如下:MOCK_METHOD宏将生成定义

MOCK_METHOD(return_type,method_name, (args...));
MOCK_METHOD(return_type,method_name, (args...), (specs...));

      参数依次是:接口返回值类型、接口名、接口形参列表。可选的第四个参数specs...是以逗号分隔的限定符列表,接收限定符包括:const、override、noexcept、Calltype(calltype)、ref(qualifier). 如果参数没有适当地用圆括号括起来,那么参数中的逗号将阻止MOCK_METHOD正确地解析参数.
      MOCK_METHOD必须在mock类定义的public部分中使用,无论被mock的方法在基类中是public, protected, 还是private.

      在gMock中,使用EXPECT_CALL宏来设置对mock方法的期望,EXPECT_CALL宏语法如下:

EXPECT_CALL(mock_object,method_name(matchers...))

      创建一种期望(expectation),设置mock object的预期行为:第一个参数是mock object;第二个参数是mock object中的方法,两者用逗号分隔,如果有参数需要同时把参数传进去
      通过EXPECT_CALL来指定Mock Object的对应行为
      EXPECT_CALL必须在执行(exercises)mock对象的任何代码之前.
      参数matchers...是一个以逗号分隔的匹配器列表(list of matchers),对应于方法method_name的每个参数。期望仅适用于参数与所有匹配器匹配的method_name调用.如果省略(matchers...),则期望的行为就像每个参数的匹配器都是通配符匹配器(_)一样。
      宏的任何一种形式都可以后跟一些可选子句,这些子句提供有关期望的更多信息。以下可链接子句(chainable clauses)可用于修改期望,并且必须按以下顺序使用:

EXPECT_CALL(mock_object, method_name(matchers...))
    .With(multi_argument_matcher)  // Can be used at most once
    .Times(cardinality)            // Can be used at most once
    .InSequence(sequences...)      // Can be used any number of times
    .After(expectations...)        // Can be used any number of times
    .WillOnce(action)              // Can be used any number of times
    .WillRepeatedly(action)        // Can be used at most once
    .RetiresOnSaturation();        // Can be used at most once

      (1).With:将期望限制为仅应用于其参数整体与多参数匹配器multi_argument_matcher匹配的mock函数调用.With子句最多可以在期望中使用一次,并且必须是第一个子句;
      (2).Times:指定期望mock函数调用的次数.参数cardinality(基数)表示期望调用的数量,可以是以下之一,都定义在::testing命名空间中:AnyNumber()、AtLeast(n)、AtMost(n)、Between(m, n)、Exactly(n) or n;
      (3).InSequence:指定mock函数调用应按特定顺序进行.参数sequences...是任意数量的序列对象.
      (4).After:指定mock函数调用顺序发生在一个或多个其它调用之后.
      (5).WillOnce:为单个匹配函数调用指定mock函数在被调用时的实际行为.参数action表示函数调用将执行的操作.
      (6).WillRepeatedly:为所有后续匹配函数调用指定mock函数在调用时的实际行为。在执行WillOnce子句中指定的操作(如果有)后生效。
      (7).RetiresOnSaturation:指示在达到期望的匹配函数调用数后,期望将不再处于活动状态.
      gMock要求在调用mock函数之前设置期望值,否则行为是未定义的。不要在调用EXPECT_CALL和调用mock函数之间交替,并且在将mock传递给API后,不要对mock设置任何期望。这意味着EXPECT_CALL应该被解读为预期将来会发生调用,而不是调用已经发生。
      如果你对参数的值不感兴趣,将_写为参数,这意味着"任何事情都会发生".如果你不关心任何参数,而不是为每个参数指定_,你可以省略参数列表,这适用于所有非重载方法.如果方法重载,则需要通过指定参数的数量以及可能的参数类型来帮助gMock解决预期的重载问题。

      ON_CALL宏语法如下:若要自定义特定mock对象的特定方法的默认操作,使用ON_CALL.它具有与EXPECT_CALL类似的语法,但它用于在不需要调用mock方法时设置默认行为

ON_CALL(mock_object,method_name(matchers...))

      gMock典型的工作流程是
      (1).从testing命名空间导入gMock名称,以便可以不限定地使用它们(每个文件只需执行一次);
      (2).创建一些mock对象;
      (3).指定你对它们的期望(一个方法将被调用多少次?用什么论证?它用过怎么做?等);
      (4).练习(exercise)一些使用mock的code;如有必要,使用GoogleTest断言检查结果;如果一个mock方法被调用的次数超过预期,或者使用了错误的参数,你将立即收到错误;
      (5).当mock被销毁时,gMock将自动检查是否满足了对它的所有期望.

      注:以上内容主要来自于GoogleTest官方文档:gMock for Dummies | GoogleTest

     以下为测试代码:

#include <string>
#include "gmock/gmock.h"

namespace gmock_ {

class Foo {
public:
	// Must be virtual as we'll inherit from Foo.
	virtual ~Foo() {}

	virtual bool SetName(const std::string& name) = 0;
	virtual std::string GetName() const = 0;
};

class MockFoo : public Foo {
public:
	MOCK_METHOD(bool, SetName, (const std::string&), (override));
	MOCK_METHOD(std::string, GetName, (), (const, override));
};

class Area {
public:
	virtual ~Area() {}
	virtual int area() = 0;
};

int GetValue(Area* p) { return p->area() / 2; }

class MockArea : public Area {
public:
	MOCK_METHOD(int, area, (), (override));
};

} // namespace gmock_

TEST(gmock, name) {
	using namespace gmock_;
	using ::testing::AtLeast;
	using ::testing::Return;

	MockFoo foo;
	EXPECT_CALL(foo, SetName("Mike"))
		.Times(AtLeast(2))
		.WillOnce(Return(1))
		.WillOnce(Return(0));
	EXPECT_TRUE(foo.SetName("Mike"));
	EXPECT_FALSE(foo.SetName("Mike"));

	EXPECT_CALL(foo, GetName())
		.Times(AtLeast(1))
		.WillRepeatedly(Return("Mike"));
	EXPECT_EQ("Mike", foo.GetName());
}

TEST(gmock, area) {
	using namespace gmock_;
	using ::testing::Return;

	MockArea m;
	EXPECT_CALL(m, area()).WillRepeatedly(Return(10));
	EXPECT_EQ(5, GetValue(&m));
}

      执行结果如下所示:

      GitHub: https://github.com/fengbingchun/Messy_Test

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

GoogleTest中gMock的使用 的相关文章

随机推荐

  • shell脚本中内嵌可执行文件/文件

    示例 test sh span class token operator span span class token operator span bin span class token operator span sh 追加在shell脚
  • 浅谈嵌入式

    浅谈嵌入式 相比耳熟能详的互联网行业 xff0c 嵌入式这几个字眼出现在公众眼前的几率可以达到忽略不计的程度 xff0c 这不仅说明嵌入式行业的工程师数量远比互联网少 xff0c 同时意味着嵌入式行业的吸引力貌似低于互联网 但是 xff0c
  • C语言系列(一):C语言程序概述

    C语言作为一种高级程序设计语言 xff0c 既有高级语言的方便性 灵活性和通用性等特点 xff0c 又兼具低级语言的特性 xff0c 提供程序员直接操作计算机硬件的功能 适合各种类型的软件开发 xff0c 深受软件工程技术人员的青睐 嵌入式
  • C语言系列(三):基本数据类型与表达式

    计算机中的数据不单是简单的数字 xff0c 所有计算机处理的信息 xff0c 包括文字 声音 图像等都是以一定的数据形式存储的 xff0c 数据在内存中保存 xff0c 存放的情况由数据类型决定 C语言的数据类型 基本类型 xff1a 整型
  • C语言系列(四): 分支结构程序设计

    选择结构是程序设计3种基本结构之一 xff0c 通过判定给定的条件是否成立选择需要执行的操作 C语言提供了条件语句 if语句和switch语句 用以实现选择结构的程序设计 xff0c 条件通常用关系表达式或逻辑表达式表示 C语言提供3种逻辑
  • C语言系列(五):循环结构程序设计

    循环结构是结构化程序设计的基本结构之一 xff0c C语言提供了三种循环结构语句 while语句 xff0c do while语句和for语句 for语句在C语言系列 xff08 二 xff09 xff1a 用C语言编写程序已经讲解 xff
  • C语言系列(六):函数与预编译处理

    模块化程序设计方法 在程序设计与开发中 xff0c 随着解决问题的复杂化 xff0c 编写程序的代码也更加复杂 一方面 xff0c 大量的程序语句会使程序的逻辑结构产生混乱 xff0c 给程序的编写 阅读和维护带来困难 xff1b 另一方面
  • Linux驱动开发经典面试简答题

    1 Linux设备中字符设备与设备有什么主要的区别 xff1f 请分别举例一些实际的设备说出它们是哪一类设备 字符设备 xff1a 字符设备是个能够像字节流 xff08 类似文件 xff09 一样被访问的设备 xff0c 由字符设备驱动程序
  • CMake中cmake_host_system_information的使用

    CMake中的cmake host system information命令用于查询各种主机系统信息 xff0c 其格式如下 xff1a cmake host system information RESULT lt variable gt
  • 一文知晓嵌入式Linux

    嵌入式Linux是什么 嵌入式Linux跟桌面Linux一样 xff0c 是一个操作系统 从单片机走过来的童鞋往往习惯于直接控制寄存器 xff0c 事必躬亲 xff0c 从零开始实现想要的功能 而在嵌入式Linux的世界里 xff0c 我们
  • 修改i.mx6ull Linux内核 启动logo

    1 制作Linux内核需要的开机logo xff08 ppm格式 xff09 1 1在Ubuntu系统上安装netpdm工具 命令如下 xff1a span class token macro property sudo apt get i
  • keil5编译错误error: #5: cannot open source input file “core_cm3.h“: No such file or directory

    用Keil vision5编译时出现 xff1a error 5 cannot open source input file core cm3 h No such file or directory 可能是MDK版本太新了 xff0c 我装
  • IPv6基础详解

    IPv6 由于internet规模的扩大 xff0c IPv4地址空间已经消耗殆尽 xff0c IETF在90年代提出了下一代互联网协议IPv6 xff0c IPv6支持几乎无限的地址空间 xff0c 并且配置更加简单 xff0c IPv6
  • Pycharm中debug使用学习

    1 运行环境 1 1 运行 xff1a 先确认项目运行环境 点击右下角python查看 向任务中添加环境 xff0c 一般加入anaconda的环境 xff0c 配置方便 切换到自己所需环境 添加运行环境 初次搭建 xff0c 哔哩哔哩中新
  • 对项目的梳理、流程和总结

    过程 我在制作 中国汽车技术研究中心 的一个演讲PPT前 xff0c 也已经有第一版的基础了 xff0c 不过 xff0c 第一版的PPT客户并不满意 xff0c 因为这个风格不是客户想要的 xff0c 所以客户对第一版的PPT并不是很满意
  • 【ROS】xxx is neither a launch file in package xxx nor is xxx a launch file name……解决

    在ros中新增加一个功能包时 xff0c 如果没有处理得当的话 xff0c 在执行时很有可能报如下错误 xff1a xxx is neither a launch file in package xxx nor is xxx a launc
  • FreeRTOS——流和消息缓冲区

    FreeRTOS 基础系列文章 基本对象 FreeRTOS 任务 FreeRTOS 队列 FreeRTOS 信号量 FreeRTOS 互斥量 FreeRTOS 任务通知 FreeRTOS 流和消息缓冲区 FreeRTOS 软件定时器 Fre
  • FreeRTOS——静态与动态内存分配

    FreeRTOS 基础系列文章 基本对象 FreeRTOS 任务 FreeRTOS 队列 FreeRTOS 信号量 FreeRTOS 互斥量 FreeRTOS 任务通知 FreeRTOS 流和消息缓冲区 FreeRTOS 软件定时器 Fre
  • CAS 6.5.5项目初始化搭建运行

    一 项目背景介绍 公司项目重构 xff0c 决定使用CAS中央认证系统 在GitHub上找到最新的稳定版本6 5 5 CAS项目在5 x版本的运行环境是jdk8 xff0c 使用maven做的项目管理 6 x使用的是jdk11作为运行环境
  • GoogleTest中gMock的使用

    GoogleTest中的gMock是一个库 xff0c 用于创建mock类并使用它们 当你编写原型或测试 prototype or test 时 xff0c 完全依赖真实对象通常是不可行或不明智的 not feasible or wise