[测试] Google Test | 主流的 C 测试框架
目录
GoogleTest
2. 准备工作
3. 测试
4.怎么用
Attention is All You Need
写项目代码的时候 边写边测试 非常重要,这样可以帮助我们减少很多的问题。
- 这篇文章后面 主要以 GoogleTest 为例,进行介绍
- 最近找了些 gtest 相关的资料,学习了下.后面主要记录了学习过程和相关知识点.
参考
初级教程
高级教程
主流框架

一、轻量级嵌入式框架(适合单片机开发)
1. SCUNIT —— 嵌入式系统的"微型工具箱"
- 特点:专为资源受限的嵌入式环境设计,核心代码仅需标准C支持,无需依赖外部库 。
- 使用场景:STM32等单片机开发,路由表、驱动模块测试。
- 使用方法:
#include "scunit.h"
void test_case() {SCUNIT_ASSERT(1+1 == 2, "算术测试"); // 类似检查螺丝刀是否拧紧
}
int main() {scunit_add_suite("基础测试");scunit_add_test("算术运算", test_case);scunit_run(); // 启动测试流水线
}
- 源码地址:SCUNIT博客介绍
2. EmbedUnit —— 嵌入式开发的"机械臂校准仪"
- 特点:完全静态内存分配,不依赖任何标准库,适合裸机开发
- 使用场景:无操作系统的微控制器测试。
- 测试示例:
TEST_ASSERT_MESSAGE(adc_value > 1000, "电压阈值检测"); // 如同检测传感器信号强度
- 项目地址:EmbedUnit官网
二、通用型框架(适合PC/服务器开发)
3. Check —— C语言的"安全气囊测试系统"
- 特点:每个测试用例运行在独立子进程,避免段错误导致整体崩溃
- 使用场景:指针操作密集的底层模块测试。
- 安装使用:
# Ubuntu安装
sudo apt-get install check
# 编写测试用例(如测试链表操作)
tcase_add_test(tc_core, test_list_insert); // 类似模拟碰撞测试
- 官网文档:Check官方指南
4. CUnit —— 企业级测试的"自动化流水线"
- 特点:支持XML输出、测试套件管理,适合大型项目
- 使用场景:持续集成环境中的回归测试。
- 示例配置:
CU_add_test(suite, "数据库连接测试", test_db_connect); // 如同质检站的多个检测环节
CU_basic_run_tests(); // 启动流水线
- 下载地址:CUnit官网
三、极简框架(适合快速验证)
5. CuTest —— 程序员的"瑞士军刀"
- 特点:仅需两个文件(CuTest.h + CuTest.c),代码量<1000行
- 使用场景:算法验证、教学演示。
- 快速上手:
CuSuite* suite = CuSuiteNew();
SUITE_ADD_TEST(suite, TestStringUtils); // 如同随身工具包中的多功能刀
CuSuiteRun(suite);
- 源码获取:CuTest GitHub镜像
6. Unity + CMocka —— 模块化开发的"乐高积木组合"
- 组合优势:
-
- Unity:断言库丰富,支持内存泄漏检测
- CMocka:提供桩函数生成,模拟外部依赖
- 典型应用:
TEST_FUNCTION(memory_alloc_test) {void* ptr = malloc(100);TEST_ASSERT_NOT_NULL(ptr); // 类似检查积木拼接是否牢固
}
- 项目资源:CMocka官网
四、跨语言框架(C/C++混合项目)
7. Google Test —— 工业级项目的"全身体检仪"
- 特点:源自Google的测试框架,支持死亡测试、参数化测试
- 适用场景:混合C/C++项目,如游戏引擎开发。
- 安装示例:
git clone https://github.com/google/googletest
cd googletest && mkdir build && cd build
cmake .. && make # 编译生成库文件
- 测试用例:
TEST(CalcTest, AddTest) {EXPECT_EQ(add(2,3), 5); // 如同X光检测骨骼强度
}
框架选择决策树
id: test-framework-choice
name: 测试框架选择指南
type: mermaid
content: |-graph TDA[项目类型?] -->|嵌入式| B{资源限制?}B -->|RAM<8KB| C[SCUNIT/EmbedUnit]B -->|资源充足| D[Check]A -->|PC/服务器| E{是否需要高级功能?}E -->|是| F[GoogleTest/CUnit]E -->|否| G[CuTest]A -->|混合C/C++| H[GoogleTest]A -->|模块隔离测试| I[Unity+CMocka]
扩展阅读
- C语言测试框架对比表
- 单元测试设计模式
选择框架时,建议优先考虑:熟悉度 > 项目需求 > 社区活跃度。就像选择汽车,超跑虽好,但日常通勤更适合经济型轿车。
GoogleTest
最近,找了些GoogleTest相关的资料,学习了下.这里主要记录了学习过程和相关知识点.
1. 什么是gtest?
- gtest测试框架是在不同平台上(Linux,Mac OS X,Windows,Cygwin,Windows CE和Symbian)为 编写C++测试而生成的。
- 它是基于xUnit架构的测试框架,支持自动发现测试
- 丰富的断言集,用户定义的断言.
关于断言,前年在学 C 语言时,有记录过 15.C与指针--超全总结

2. 准备工作
获取gtest源码: https://github.com/google/googletest.git

在shell下:
cd googletest/
cmake ..
make
成功后得到静态库文件:

将libgtest.a libgtest_main.a拷贝到main.cpp同级目录下(main.cpp自己创建)
cp googletest/bulid/lib/libgtest*.a .
3. 测试
先搞个例子跑起来.
main.cpp
/* main.cpp* Created by lvy on 2025/4/1.*/
#include "gtest/gtest.h"
#include <iostream>
#include <string>int add(int a, int b)
{return a + b;
}TEST(fun, add_a)
{EXPECT_EQ(-3, add(-2,-1));EXPECT_EQ(-2, add(1,-3));
}int main(int argc, char **argv){::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();return 0;
}
关于库的一些详细信息,我们也可以跳转进行查看

哦对,还发现了一个看注释的翻译插件挺好用的:

可以更方便的看源码了

编译:
g++ main.cpp libgtest.a -lpthread -std=c++17 -I /home/lvy/OS_AI/gtest/goo
gletest/googletest/include -o m
(由于gtest版本问题,12.x 必须c++17以上才能编译通过,刚开始编译用的11标准,一直报错)
(有用的就是静态库和头文件,将来移植的时候就是需要这两个东西)

还是 那句话,相信机器永远是对的~
这样就算可以用啦.后面具体讲一下,gtest怎么用.
4.怎么用
断言
分 ASSERT_XXX 和 EXPECT_XXX 两类.
区别:
- 如果 ASSERT_XXX 测试结果不通过, 后面的测试就不会执行了.
- 如果 EXPECT_XXX 测试结果不通过, 后面的测试会接着执行.
布尔断言:单参断言
- ASSERT_TRUE、ASSERT_FALSE、EXPECT_TRUE、EXPECT_FALSE
数值断言:双参
- ASSERT_EQ、ASSERT_NE、ASSERT_LT、ASSERT_LE、ASSERT_GT、ASSERT_GE
- EXPECT_EQ、EXPECT_NE、EXPECT_LT、EXPECT_LE、EXPECT_GT、EXPECT_GE
字符串断言
- ASSERT_STREQ、ASSERT_STRCASEEQ
TEST(test_suite_name,test_name)
- 一个TEST()算是一个测试case.
- TEST(x,y)展开为x_y_TEST()这样的函数
比如测试add()函数,我们可以考虑多种测试情况: 和为负数, 和为正数, 极限值测试.
/* main.cpp* Created by lvy on 2025/4/1.*/
#include "gtest/gtest.h"
#include <iostream>
#include <string>int add(int a, int b)
{return a + b;
}TEST(add, negative)
{EXPECT_EQ(-3, add(-2,-1));EXPECT_EQ(-2, add(1,-3));
}TEST(add, positive)
{EXPECT_EQ(1, add(2,-1));EXPECT_EQ(2, add(-1,3));
}TEST(add, limit)
{int a = 0x7fffffff + 1;std::cout<<"a = "<<a<<"\n";EXPECT_EQ(a, add(0x7fffffff,1));EXPECT_EQ(0, add(0xffffffff,1));
}int main(int argc, char **argv){::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();return 0;
}

TEST_F(x,y)
以下函数使用需要定义测试套类继承::testing::Test,重新实现对应函数.
- Set UpTest Suite:static测试套级别,运行测试套 第一个用例前执
- Tear DownTest Suite: static 测试套级别,运行测试套 最后一个用例后执行
- Set Up:virtual 测试套中每个测试用例 开始时执行
- Tear Down:virtrual 测试套中每个测试用例运行后执行
x 为 class名.
[怎么理解,举个例子:
- TEST()适用于单次api测试,但是通常我们都是以模块或者功能进行开发的
- 比如我们写了一个链表,链表里面有很多api:添加,删除,比较,等.
对于整个链表的测试就是套件级别的,里面的api就是test级别的.
- TEST_F(list, add)
- TEST_F(list, delete)
/* main.cpp* Created by lvy on 2025/4/1.*/
#include "gtest/gtest.h"
#include <iostream>
#include <string>int add(int a, int b)
{return a + b;
}TEST(add, negative)
{EXPECT_EQ(-3, add(-2,-1));EXPECT_EQ(-2, add(1,-3));
}TEST(add, positive)
{EXPECT_EQ(1, add(2,-1));EXPECT_EQ(2, add(-1,3));
}TEST(add, limit)
{int a = 0x7fffffff + 1;std::cout<<"a = "<<a<<"\n";EXPECT_EQ(a, add(0x7fffffff,1));EXPECT_EQ(0, add(0xffffffff,1));
}class FooTest : public ::testing::Test {protected:// You can remove any or all of the following functions if their bodies would// be empty.FooTest() {// You can do set-up work for each test here.}~FooTest() override {// You can do clean-up work that doesn't throw exceptions here.}static void SetUpTestSuite() {std::cout<<"===================run before first case..."<<std::endl;} static void TearDownTestSuite() {std::cout<<"===================run after last case..."<<std::endl;}// If the constructor and destructor are not enough for setting up// and cleaning up each test, you can define the following methods:void SetUp() override {std::cout<<" =========================SetUp() \n";// Code here will be called immediately after the constructor (right// before each test).}void TearDown() override {std::cout<<" =========================TearDown() \n";// Code here will be called immediately after each test (right// before the destructor).}// Class members declared here can be used by all tests in the test suite// for Foo.
};TEST_F(FooTest,test_a)
{EXPECT_EQ(2, add(0x7fffffff,1));
}TEST_F(FooTest,test_b)
{EXPECT_EQ(1, add(0,1));
}int main(int argc, char **argv){::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();return 0;
}

上面两个是常用的.基本上就是初级教程里面的内容,高级教程后面有链接.
初级教程
高级教程

关于汽车软件测试的拓展阅读:
相关文章:
[测试] Google Test | 主流的 C 测试框架
目录 GoogleTest 2. 准备工作 3. 测试 4.怎么用 Attention is All You Need 写项目代码的时候 边写边测试 非常重要,这样可以帮助我们减少很多的问题。 这篇文章后面 主要以 GoogleTest 为例,进行介绍最近找了些 gtest 相关的资料,学习了下.后面主要…...
OpenCV 图形API(3)高层次设计概览
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 描述 G-API 是一个异构框架,提供了统一的 API 来使用多个支持的后端编程图像处理流水线。 关键的设计理念是在指定使用哪些内核和设备时保持流…...
51单片机的五类指令(五)——位操作类指令
目录 一、位传送指令 1、MOV C, bit 2、MOV bit, C 3、位传送指令的应用场景 二、位变量修改指令 1、CLR(清 0 指令) 2、SETB(置 1 指令) 3、位变量修改指令的应用场景 三、位变量逻辑操作指令 1、位变量逻辑与指令 ANL…...
用python编写poc的流程
目录 一、POC 编写核心流程 二、常用 Python 库与工具 三、POC 框架推荐 四、高级优化技巧 五、安全规范与注意事项 六、实战案例:命令注入漏洞验证 一、POC 编写核心流程 漏洞分析 确定漏洞类型:根据目标特征判断漏洞类型(如 SQL 注入、…...
碰一碰发视频网页版本开发的源码搭建指南
引言 在数字化信息快速传播的时代,近场通信(NFC)技术为信息交互带来了新的便捷方式。通过网页版本实现碰一碰发视频功能,能够让用户在浏览器环境中轻松实现视频分享,拓展了视频传播的途径。本文将详细介绍碰一碰发视频…...
【含文档+PPT+源码】基于Python爬虫二手房价格预测与可视化系统的设计与实现
项目介绍 本课程演示的是一款基于Python爬虫二手房价格预测与可视化系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 带你从零开始部署运行本套系统 该项…...
多台服务器上docker部署 Redis 集群
规划集群节点 确保你的服务器有固定 IP,比如: 172.16.17.100 172.16.17.101 172.16.17.102 每台服务器运行 2 个 Redis 节点,总共 6 个节点,满足 Redis Cluster 最小节点数要求。 2. 在每台服务器上运行 Redis 在每台服务器上执行…...
Redis-16.在Java中操作Redis-Spring Data Redis使用方式-操作有序集合类型的数据
一. 操作有序集合类型的数据 package com.sky.test;import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.*;imp…...
针对单台浪潮服务器运行Windows Server 2019和SQL Server的MES系统场景、高效能监控策略(兼顾软硬件健康)
--- ### **一、监控架构设计原则** - **轻量化**:优先使用Windows原生工具和免费方案,避免额外资源消耗 - **关键性聚焦**:仅监控直接影响MES运行的核心指标 - **自动化告警**:异常发生时主动触发通知,无需人工巡检 -…...
Vue Transition组件类名+TailwindCSS
#本文教学结合TailwindCSS实现一个Transition动画的例子# 举例代码: <transition enter-active-class"transition-all duration-300 ease-out"enter-from-class"opacity-0 translate-y-[-10px]"enter-to-class"opacity-100 translate-…...
Anaconda和Pycharm的区别,以及如何选择两者
目录 主要区别详细说明如何选择?Anaconda的使用步骤 主要区别 Anaconda 和 PyCharm 是 Python 开发中常用的两个工具,但它们的定位和功能完全不同。以下是它们的主要区别: 对比项AnacondaPyCharm类型Python 发行版 包管理工具Python 集成开…...
STM32智能手表——任务线程部分
RTOS和LVGL我没学过,但是应该能硬啃这个项目例程 ├─Application/User/Tasks # 用于存放任务线程的函数 │ ├─user_TaskInit.c # 初始化任务 │ ├─user_HardwareInitTask.c # 硬件初始化任务 │ ├─user_RunModeTasks.c…...
SQL命令
一、表的创建 SQL MS Access、MySQL 和 SQL Server 数据类型 | 菜鸟教程 SQL Server 和 MySQL 中的 Date 函数 | 菜鸟教程 1.1、创建表 CREATE TABLE Citys (CityID int PRIMARY KEY,CityName varchar(255) );CREATE TABLE Per (PersonID int PRIMARY KEY, …...
DRM_CLIENT_CAP_UNIVERSAL_PLANES和DRM_CLIENT_CAP_ATOMIC
drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1); 这两行代码用于启用 Linux DRM(Direct Rendering Manager)客户端的两个关键特性,具体作用如下: 1. drmSetClientCap…...
anaconda安装 创建虚拟环境+pycharm中conda环境配置
miniconda下载安装参考以下链接: https://blog.csdn.net/2301_76831056/article/details/143165738?fromshareblogdetail&sharetypeblogdetail&sharerId143165738&sharereferPC&sharesourceweixin_63339973&sharefromfrom_link (注…...
EasyExcel导出导入excel工具类
接上一篇EasyExcel导出导入excel的文章,附上一份完整的工具类代码。对于字体颜色名称,请参考这篇文章。 POI字体颜色 小技巧 类转换用属性拷贝不同类如果有相同属性,则使用反射验证,减少代码量 private List<Person> vali…...
终端SSH连接工具SecureCRT安装和连接Linux
SecureCRT 9.5是一款集终端仿真与加密功能于一身的专业软件,其坚如磐石的安全性、高效的信息传输能力以及高度可定制的会话管理,使得它成为众多用户的首选。该软件不仅支持SSH2、SSH1、Telnet等多种协议,还提供了Relogin、Serial、TAPI、RAW等…...
赛逸展2025“创新引擎”启动:限量席位,点亮科技绿色新征程
当今时代,科技革新与绿色发展已然成为推动社会进步的双引擎。2025第七届亚洲消费电子技术贸易展(赛逸展)敏锐捕捉这一趋势,重磅打造“科技创新专区”,并面向科技、绿色企业吹响限量招募号角。 这个独具特色的专区紧扣…...
Spring的 init-method, @PostConstruct, InitializingBean 对比
Spring的 init-method, PostConstruct, InitializingBean 对比 在Spring框架中,init-method、PostConstruct和InitializingBean都是用于定义Bean初始化后执行逻辑的机制,但它们在实现方式、耦合度、执行顺序及适用场景上有所不同。以下是它们的对比总结…...
Gogs 精简备份与恢复方案(仅SQLite数据库和配置)
一、备份方案设计 1. 备份内容 SQLite数据库文件:/home/git/gogs/data/gogs.db 配置和附件:/home/git/gogs/custom 整个目录 2. 备份策略 每周日凌晨2点执行完整备份 保留最近4周的备份文件 备份存储在独立分区 /backup(使用永久化挂载…...
FPGA实现数码管显示分秒时间
目录 一. verilog实现 二. 烧录验证 三. 结果验证 使用开发板:DE2-115开发板 一. verilog实现 要实现分和秒,需要知道定时器的频率,通过查手册可知,我使用的开发板时钟为50hz,也就是时钟一个周期是2微秒。 5000000…...
读书记录九之《在峡江的转弯处-陈行甲人生笔记》
距离上本读完的书,写读后感有很长一段时间了,中间读了几本书,但都没写点文字,没错,是懒病又犯了。陈行甲这本书,一开始从网络上推荐看到,看之前介绍是一本人物自传的回忆录。我个人对这类贴近的…...
可视化开发:用Qt实现Excel级动态柱状图
Qt柱状图 QtChart 首先我们介绍一下 图表建立的基础:Qt Charts QtChart 是Qt框架的一个模块,专注与提供交互式数据可视化功能 俗话就是 用于用户轻松创建各种类型的图表和图形界面 它包含的图表类型有很多:折线图,饼图&#x…...
从零实现Json-Rpc框架】- 项目实现 - 基于Dispatcher模块的RPC框架
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
kubekey -实现懒人一键部署K8S集群
kubekey -实现懒人一键部署K8S集群 操作步骤 官网: https://kubesphere.io/zh/ 一、执行以下命令快速创建一个 Kubernetes 集群。 Master节点 如果您访问 GitHub/Googleapis 受限,请登录 Linux 主机,执行以下命令设置下载区域。 [roottest ~]…...
Android设计模式之模板方法模式
一、定义: 定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 二、结构: AbstractClass抽象类:定义算法的骨架,包含模板方法和若干…...
李宏毅机器学习笔记(1)—机器学习基本概念+深度学习基本概念
机器学习基本概念 1、获取模型 步骤 1.1、假定未知函数 带未知参数的函数 1.2、定义损失函数 真实值:label MAE MSE 几率分布,cross-entropy? 1.3、优化 单独考虑一个参数 让损失函数最小,找导数为零的点 单独考虑w,w…...
数字IC后端项目常见问题之streamOut layermap和innovus drc violation
Q1:我需要将Innovus设计GDS导出到Virtuoso,但发现写出GDS的过程会报如下所示的警告。这里写出GDS使用的是Virtuoso (DFII) streamOut mapping文件! Clock Gen模块Routing DRC,Timing分析及解决 streamOut tease.gds2 -mapFile cd…...
短剧系统开发动漫短剧系统源码开发上线小程序app教程
一、市场规模与用户增长:突破677亿,Z世代成主力 整体扩张 2025年短剧市场预计同比增长15%,规模达677.9亿元,用户规模6.62亿(占网民59.7%)。动漫短剧作为细分领域,增速显著受益于二次元文化渗透&…...
太阳能高杆路灯:照亮未来的新光
在全球能源转型进程加速以及可持续发展理念日益深入人心的背景下,太阳能高杆路灯作为融合新能源技术、智能控制技术与多功能集成特性的创新产品,正逐步革新传统路灯的格局。其不仅有效解决了传统路灯对电网供电的依赖问题,更为城市及乡村的照…...
