CppUTest是专为嵌入式C/C++设计的轻量测试框架,不依赖STL或异常,编译快、断言轻、内存泄漏检测开箱即用;它仅用C++98子集,通过TEST_GROUP组织测试,自动管理对象生命周期,并提供EXPECT_THROW等专用宏支持异常和浮点精度断言。

直接用 CppUTest 写,别绕弯——它专为 C/C++ 嵌入式场景设计,不依赖 STL 或异常,编译快、断言轻、内存泄漏检测开箱即用。
为什么不用 Google Test 或 Catch2?
Google Test 默认启用 RTTI 和异常,某些嵌入式工具链(如 IAR、Keil ARMCC)不支持;Catch2 的模板深度和头文件体积在资源受限环境下容易触发编译器限制。而 CppUTest 只用 C++98 子集,#include "CppUTest/CppUTest.h" 后就能跑,无运行时依赖。
- 如果你的项目已用
std::unique_ptr或std::thread,说明环境较宽松,可选 Google Test;但若目标平台是裸机、RTOS 或旧编译器,CppUTest是更稳的选择 -
CppUTest的TEST_GROUP机制天然匹配类的测试组织:一个类对应一个测试组,成员变量自动在每个TEST前重置,避免静态状态污染 - 它的内存泄漏检测(
-r100重复跑 +-s123随机顺序)能暴露单例、静态缓存等隐藏耦合,这点比多数框架更实用
怎么写一个 Calculator 类的测试?
假设你有如下 Calculator 类:
class Calculator {
public:
double add(double a, double b) { return a + b; }
double divide(double a, double b) {
if (b == 0.0) throw std::invalid_argument("division by zero");
return a / b;
}
};对应测试应这样组织:
立即学习“C++免费学习笔记(深入)”;
- 用
TEST_GROUP(Calculator)定义测试组,内部声明Calculator* calc; - 在
setup()中calc = new Calculator();,teardown()中delete calc;—— 不用手动管理生命周期 - 断言用
LONGS_EQUAL、DOUBLES_EQUAL,不是ASSERT_EQ;浮点比较必须带精度,比如DOUBLES_EQUAL(5.0, calc->add(2.1, 2.9), 0.001) - 异常测试不能靠
try/catch手写,要用EXPECT_THROW宏:EXPECT_THROW(calc->divide(1.0, 0.0), std::invalid_argument);
main 函数和命令行怎么配?
入口函数极简,只要两行:
#include "CppUTest/CommandLineTestRunner.h"
int main(int ac, char** av) { return CommandLineTestRunner::RunAllTests(ac, av); }编译后可直接用命令行控制行为:
-
./test -v:逐个打印测试名,方便定位卡在哪 -
./test -g Calculator:只跑Calculator组,开发时省时间 -
./test -r3 -s42:重复跑 3 次并打乱顺序,查静态变量残留或初始化顺序 bug -
./test -f:失败时直接abort(),配合gdb抓 core 更准
注意:CppUTest 不自动链接 stdc++,链接时得显式加 -lcpputest -lcpputest_main,否则报 undefined reference to 'TestRegistry::getCurrentRegistry()'。
CMake 集成最容易踩的坑
用 FetchContent 最省心,但别漏掉三件事:
-
FetchContent_Declare必须指定GIT_TAG v4.0(当前稳定版),用master会因接口变动导致编译失败 -
FetchContent_MakeAvailable后要调target_link_libraries(your_test PRIVATE cpputest_main),只链cpputest会缺RUN_ALL_TESTS符号 - 如果项目用了
-std=c++17,需给cpputest单独设set_property(TARGET cpputest PROPERTY CXX_STANDARD 98),否则宏展开报错
真实项目里,最常被忽略的是 teardown() 里没删对象,或测试中用了全局 static 缓存——CppUTest 的重复运行模式(-r)会立刻暴露这类问题,别等 CI 报了才修。


















