玩转单元测试之gtest
引言
程序开发的时候,往往需要编写一些测试样例来完成功能测试,以保证自己的代码在功能上符合预期,能考虑到一些异常边界问题等等。
gtest快速入门
1.引入gtest
# 使用的是1.10版本,其他版本可根据需要选择
git clone -b v1.10.x https://github.com/google/googletest.git
cd googletest
mkdir build && cd build
cmake .. && make -j4
sudo make install
sudo ldconfig
2.编写第一个单测
2.1 待测试文件
#ifndef __HELLO_H__
#define __HELLO_H__#include <iostream>
#include <string>class Animal {
public:Animal(std::string name) : _name(name){}virtual ~Animal() {}virtual bool eat(const std::string& food) = 0;private:std::string _name;
};class Tigger : public Animal {
public:Tigger() : Animal("tigger"){}bool eat(const std::string& food) override{if (food == "meat") {return true;}return false;}
};class Horse : public Animal {
public:Horse() : Animal("Horse"){}bool eat(const std::string& food) override{if (food == "grass") {return true;}return false;}
};
#endif
2.2 单测文件
#include "hello.h"
#include "gtest/gtest.h"using namespace ::testing;namespace {
TEST(TestTigger, CaseEat)
{Animal *tigger = new Tigger();bool ret = tigger->eat("meat");EXPECT_TRUE(ret);ret = tigger->eat("grass");EXPECT_FALSE(ret);delete tigger;
}TEST(TestHorse, CaseEat)
{Animal *horse = new Horse();bool ret = horse->eat("grass");EXPECT_TRUE(ret);ret = horse->eat("meat");EXPECT_FALSE(ret);delete horse;
}
}
2.3 makefile文件
CXX = g++
CXXFLAGS = -Wall
LIBES = -lgtest -lgtest_main -lpthread
LPATH = -L/tools/googletest/1.11.0/build/lib # 替换成自己lib路径
HPATH = -I/tools/googletest/1.11.0/googletest/include/ # 替换成自己的include路径UTEST_OBJD = hello_unit_testhello_unit_test:hello_unit_test.cpp${CXX} -o $@ $+ -I ../ ${HPATH} ${CXXFLAGS} ${LIBES} ${LPATH}clean:rm -rf *_unit_test
make && ./hello_unit_test 编译并执行单测程序,执行结果如下:

gtest常用宏
1. 各种断言
1.1 Bool断言
| 致命断言 | 非致命断言 | 含义 |
|---|---|---|
| ASSERT_TRUE(val) | EXPECT_TRUE(val) | val == true |
| ASSERT_FALSE(val) | EXPECT_FALSE(val) | val == false |
1.2 二元值断言(比较大小)
| 致命断言 | 非致命断言 | 含义 |
|---|---|---|
| ASSERT_EQ(a, b) | EXPECT_EQ(a, b) | a == b |
| ASSERT_NE(a, b) | EXPECT_NE(a, b) | a != b |
| ASSERT_LT(a, b) | EXPECT_LT(a, b) | a < b |
| ASSERT_LE(a, b) | EXPECT_LE(a, b) | a <= b |
| ASSERT_GT(a, b) | EXPECT_GT(a, b) | a > b |
| ASSERT_GE(a, b) | EXPECT_GE(a, b) | a >= b |
1.3 字符串断言(字符串比较)
| 致命断言 | 非致命断言 | 含义 |
|---|---|---|
| ASSERT_STREQ(a, b) | EXPECT_STREQ(a, b) | a == b |
| ASSERT_STRNE(a, b) | EXPECT_STRNE(a, b) | a != b |
| ASSERT_STRCASEEQ(a, b) | EXPECT_STRCASEEQ(a, b) | a == b 忽略大小写 |
| ASSERT_STRCASENE(a, b) | EXPECT_STRCASENE(a, b) | a != b 忽略大小写 |
2. TEST、TEST_F和TEST_P
2.1 TEST
TEST是最基本的构造测试case的宏,基本用法:
TEST(param1, prama2)
{
/*测试代码*/
}
- 参数1:用例名,一般由待测试的类名或函数名组成,如TestAnimal
- 参数2:测试名,代表测试含义,如CaseEat
- 测试结果将以"用例名.测试名"来区分不同测试case
2.2 TEST_F
TEST_F和TEST的不同之处在于,其可以使用到初始化函数(SetUp)和一个清理函数(TearDown)。基本用法如下:
class TestAnimal : public ::testing::Test {
protected:void SetUp() override{// 成员变量初始化tigger = new Tigger();}void TearDown() override{// 资源清理、释放delete tigger;tigger = NULL;}
protected:Animal *tigger;
};TEST_F(TestAnimal, caseEatMeat)
{ // 执行之前调用SetUp进行初始化EXPECT_TRUE(tigger->eat("meat"));// case退出时调用TearDown进行释放
}TEST_F(TestAnimal, caseEatGrass)
{// 执行之前调用SetUp进行初始化EXPECT_FALSE(tigger->eat("grass"));// case退出时调用TearDown进行释放
}
- 创建一个继承testing::Test的测试类TestAnimal,并在该类中声明成员变量,做好初始化和清理操作
- TEST_F宏
- 参数1:同测试类名(TestAnimal )
- 参数2:测试名,代表测试含义
- 每一个测试case都是相互独立的,当每个case需要共同使用某个变量时,可以将该变量放在测试类中,每执行一个TEST_F宏构造的case,都会调用一次SetUp和TearDown,因此case之间对变量的操作不会相互影响。
2.3 TEST_P
针对某个待测试的方法,当你需要测试不同的输入,但又不想每个case都写一遍时,就可以使用到TEST_P宏,基本使用如下:
// 多个参数时,使用结构体更方便
struct MyParams {std::string food;// other params
};
class TestAnimal : public ::testing::Test, public ::testing::WithParamInterface<MyParams>
{
protected:void SetUp() override{// 成员变量初始化tigger = new Tigger();}void TearDown() override{// 资源清理、释放delete tigger;tigger = NULL;}
protected:Animal *tigger;
};TEST_P(TestAnimal, caseEat)
{std::string food = GetParam().food; // 获取参数ASSERT_FALSE(tigger->eat(food));
}// 构造不同的测试样例
INSTANTIATE_TEST_SUITE_P(TestCaseEatParams, TestAnimal, ::testing::Values(MyParams{"grass"},MyParams{"leafs"}
));
- 和TEST_F有相似的功能,使用SetUp、TearDown进行初始化和清理,创建一个继承testing::Test、testing::WithParamInterface的测试类,其中WithParamInterface是一个模板类,用来关联测试参数。
- TEST_P宏
- 参数1:测试类名
- 参数2:测试名,代表测试含义
- INSTANTIATE_TEST_SUITE_P宏
- 参数1:能表明测试含义即可
- 参数2:测试类名
- 参数3:不同测试样例集合
- 执行结果如下:

总结
- 好记性不如烂笔头,最近在写单元测试,于是就有了这篇文章。
- 通过学习gtest的基本语法,已经可以应对一部分测试场景了,然而还有一些场景只通过gtest是无法完成的,比如,在我们的代码中有许多并不是我们自己设计的接口,可能是外部依赖,也可能来自于其他模块,我们没办法设计一个合适的case来让这些接口返回给我们一个预期值,那我们该怎么办呢?于是gmock由此诞生,这个在下一篇中会进行深入学习,篇名我已经想好了(玩转单元测试之GMock)。
相关文章:
玩转单元测试之gtest
引言 程序开发的时候,往往需要编写一些测试样例来完成功能测试,以保证自己的代码在功能上符合预期,能考虑到一些异常边界问题等等。 gtest快速入门 1.引入gtest # 使用的是1.10版本,其他版本可根据需要选择 git clone -b v1.1…...
Tomcat 一次请求的生命周期
在使用 Tomcat 的时候,我们只需要在 Servlet 实现类中写我们的业务逻辑代码即可,不需要管 Socket 连接、协议处理要怎么实现,因为这部分作为不经常变动的部分,被封装到了 Tomcat 中,程序员只需要引入 Tomcat 中即可&am…...
spring cloud gateway中配置uri
gateway中配置uri配置有三种方式: websocket方式:uri: ws://localhost:9000http方式: uri: http://localhost:8130/lb注册中心配置方式(注册的服务名称): uri: lb://monitor-ms gateway的lb方式识别的服务名称命名规则: "[…...
使用NAudio录制wav音频
NAudio NAudio官网 环境 Unity2019.4.34f1c1 Window10 NAudio 1.10 .Net 3.5 录制音频 WaveInEvent类可录制音频 StartRecording方法 启用录制StopRecording方法 停止录制DataAvailable 录制中回调RecordingStopped 录制结束回调 WaveFileWriter类可存储音频 Write方法…...
数据结构之动态内存管理机制
目录 数据结构之动态内存管理机制 占用块和空闲块 系统的内存管理 可利用空间表 分配存储空间的方式 空间分配与回收过程产生的问题 边界标识法管理动态内存 分配算法 回收算法 伙伴系统管理动态内存 可利用空间表中结点构成 分配算法 回收算法 总结 无用单元收…...
【汇编语言】栈及栈操作的实现
文章目录 栈结构栈操作栈的小结 栈结构 栈是一种只能在一端插入或删除的数据结构;栈有两个基本的操作:入栈和出栈; 入栈:将一个新的元素放到栈顶;出栈:从栈顶取出一个元素; 栈的操作规则&#…...
【JavaEE】面向切面编程AOP是什么-Spring AOP框架的基本使用
【JavaEE】Spring AOP(1) 文章目录 【JavaEE】Spring AOP(1)1. Spring AOP 是什么1.1 AOP 与 Spring AOP1.2 没有AOP的世界是怎样的1.3 AOP是什么 2. Spring AOP 框架的学习2.1 AOP的组成2.1.1 Aspect 切面2.1.2 Pointcut 切点2.1…...
SpringBoot+微信小程序奶茶在线点单小程序系统 附带详细运行指导视频
文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码 一、项目演示 项目演示地址: 视频地址 二、项目介绍 项目描述:这是一个基于SpringBoot微信小程序框架开发的奶茶在线点单小程序系统。首先,这是一个前后端分离的项目ÿ…...
【支付宝小程序】开发基础--文件结构教程
🦖我是Sam9029,一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 🐱🐉🐱🐉恭喜你,若此文你认为写的不错,不要吝啬你的赞扬,求收…...
LLM 生成式配置的推理参数温度 top k tokens等 Generative configuration inference parameters
在这个视频中,你将了解一些方法和相关的配置参数,这些参数可以用来影响模型在下一个词生成时的最终决策方式。如果你在Hugging Face网站或AWS的游乐场中使用过LLMs,你可能已经看到了这些控制选项,用来调整LLM的行为。每个模型都暴…...
npm的镜像源和代理的查看和修改
一、镜像源 查询当前镜像源 npm get registry 设置为淘宝镜像 npm config set registry http://registry.npm.taobao.org/ 设置回默认的官方镜像 npm config set registry https://registry.npmjs.org/ 设置electron为淘宝镜像 npm config set ELECTRON_MIRROR "h…...
IP库新增经过实践的Verilog 库
网上严重缺乏实用的 Verilog 设计。Project F 库是尝试让 FPGA 初学者变得更好部分。 设计包括 Clock- 时钟生成 (PLL) 和域交叉Display - 显示时序、帧缓冲区、DVI/HDMI 输出Essential- 适用于多种设计的便捷模块Graphics- 绘制线条和形状Maths- 除法、LFSR、平方根、正弦....…...
SLAM-VIO视觉惯性里程计
SLAM 文章目录 SLAM前言IMU与视觉比较单目视觉缺陷:融合IMU优势:相机-IMU标定松耦合紧耦合基于滤波的融合方案:基于优化的融合方案: 前言 VIO(visual-inertial odometry)即视觉惯性里程计,有时…...
分布式 RPC 框架入门
分布式 RPC 框架入门 警告 torch.distributed.rpc 程序包是实验性的,随时可能更改。 它还需要 PyTorch 1.4.0才能运行,因为这是第一个支持 RPC 的版本。 本教程使用两个简单的示例来演示如何使用 torch.distributed.rpc 软件包构建分布式训练…...
Spring boot与Spring cloud 之间的关系
Spring boot与Spring cloud 之间的关系 Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务,Spring Boot,看名字就知道是Spring的引导,就是用于启动Spring的,使得Spring的学习和使用…...
报名开启 | HarmonyOS第一课“营”在暑期系列直播
<HarmonyOS第一课>2023年再次启航! 特邀HarmonyOS布道师云集华为开发者联盟直播间 聚焦HarmonyOS 4版本新特性 邀您一同学习赢好礼! 你准备好了吗? ↓↓↓预约报名↓↓↓ 点击关注了解更多资讯,报名学习...
Apache DolphinScheduler 支持使用 OceanBase 作为元数据库啦!
DolphinScheduler是一个开源的分布式任务调度系统,拥有分布式架构、多任务类型、可视化操作、分布式调度和高可用等特性,适用于大规模分布式任务调度的场景。目前DolphinScheduler支持的元数据库有Mysql、PostgreSQL、H2,如果在业务中需要更好…...
matlab使用教程(17)—广度优先和深度优先搜索
1.可视化广度优先搜索和深度优先搜索 此示例说明如何定义这样的函数:该函数通过突出显示图的节点和边来显示 bfsearch 和 dfsearch 的可视化结果。 创建并绘制一个有向图。 s [1 2 3 3 3 3 4 5 6 7 8 9 9 9 10]; t [7 6 1 5 6 8 2 4 4 3 7 1 6 8 2]; G dig…...
CSerialPort教程4.3.x (2) - CSerialPort源码简介
CSerialPort教程4.3.x (2) - CSerialPort源码简介 前言 CSerialPort项目是一个基于C/C的轻量级开源跨平台串口类库,可以轻松实现跨平台多操作系统的串口读写,同时还支持C#, Java, Python, Node.js等。 CSerialPort项目的开源协议自 V3.0.0.171216 版本…...
【数据结构OJ题】有效的括号
原题链接:https://leetcode.cn/problems/valid-parentheses/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 这道题目主要考查了栈的特性: 题目的意思主要是要做到3点匹配:类型、顺序、数量。 题目给的例子是比较…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...
标注工具核心架构分析——主窗口的图像显示
🏗️ 标注工具核心架构分析 📋 系统概述 主要有两个核心类,采用经典的 Scene-View 架构模式: 🎯 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 🔧 关键函数&…...
