第9章:CTest入门:CTest是什么?CTest与CMake的关系、启用测试(enable_testing)
9.1 CTest到底是什么?
CTest,说白了就是CMake自带的测试工具。它不是第三方库,也不是什么高大上的框架。它就是CMake家族里专门负责跑测试的那个兄弟。
我个人习惯把CTest理解成「测试调度员」。你写好了测试用例,CTest帮你一个个跑,跑完了告诉你哪些过了、哪些挂了、挂了的原因是什么。就这么简单。
我记得刚接触CTest时,总觉得它跟Google Test、Catch2这些测试框架是一回事。后来才搞明白——CTest不负责写测试,它只负责跑测试。测试用例本身还是用你喜欢的框架写,CTest只是那个「监考老师」。
一句话总结:CTest = 测试运行器 + 测试报告生成器。它不写测试,只管跑。
9.2 CTest与CMake的关系
CTest是CMake的一部分。你装了CMake,CTest就自动装好了。它们的关系就像「锅和锅盖」——分不开。
具体来说,CMake负责构建项目,CTest负责测试项目。流程是这样的:
- CMake配置项目,生成构建文件
- 你编译项目,生成可执行文件
- CTest读取CMake中定义的测试,逐个运行
- CTest收集结果,生成报告
嗯,这里要注意:CTest本身不编译代码。你得先编译好,它才能跑。我在项目中遇到过有人以为CTest会自动编译测试——结果折腾了半天,测试文件还是旧的。
小技巧:你可以用 ctest --build-and-test 让CTest先编译再测试,但我个人建议分开做。编译归编译,测试归测试,出了问题好排查。
9.3 启用测试:enable_testing()
要让CTest工作,第一步就是在CMakeLists.txt里调用 enable_testing()。这个命令告诉CMake:「嘿,这个项目要跑测试,给我准备好测试环境。」
它的用法极其简单:
# 在顶层CMakeLists.txt中
cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
enable_testing() # 启用测试支持
# ... 其他构建逻辑 ...
add_executable(my_test test_main.cpp)
add_test(NAME MyBasicTest COMMAND my_test)
你想想看,就这么一行代码,CTest就能接管你的测试流程了。
我曾经踩过的坑:enable_testing() 必须在顶层CMakeLists.txt中调用。如果你在子目录里调用,CTest会报错说找不到测试。别问我怎么知道的——我当年在一个大项目里折腾了整整一下午。
9.4 add_test():注册测试用例
启用测试后,下一步就是用 add_test() 注册具体的测试用例。基本语法:
add_test(NAME <测试名称> COMMAND <可执行文件> [参数...])
举个例子:
add_executable(test_math test_math.cpp)
add_test(NAME MathTest COMMAND test_math)
add_executable(test_string test_string.cpp)
add_test(NAME StringTest COMMAND test_string --verbose)
这里我用了两个不同的测试可执行文件。CTest会依次运行它们,并报告结果。
我个人习惯给测试命名时加上前缀或分类,比如 Unit_MathTest、Integration_DatabaseTest。这样在CTest里可以按模式筛选运行:
# 只跑单元测试
ctest -R "^Unit_"
# 跳过集成测试
ctest -E "^Integration_"
9.5 知识体系总览
下面这张图帮你理清CTest、CMake和测试框架之间的关系:
9.6 一个完整的例子
光说不练假把式。我们来看一个完整的项目结构:
my_project/
├── CMakeLists.txt # 顶层
├── src/
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── math_utils.cpp
└── tests/
├── CMakeLists.txt
└── test_math_utils.cpp
顶层 CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
enable_testing() # 启用测试
add_subdirectory(src)
add_subdirectory(tests)
tests/CMakeLists.txt:
add_executable(test_math_utils test_math_utils.cpp)
target_link_libraries(test_math_utils PRIVATE MyProjectLib)
add_test(NAME MathUtilsTest COMMAND test_math_utils)
然后编译、测试:
mkdir build && cd build
cmake ..
make
ctest # 或者 ctest -V 显示详细信息
输出大概长这样:
Test project /path/to/build
Start 1: MathUtilsTest
1/1 Test #1: MathUtilsTest ............... Passed 0.02 sec
100% tests passed, 0 tests failed out of 1
个人经验:我习惯在项目根目录放一个 run_tests.sh 脚本,里面就两行:cd build && ctest --output-on-failure。这样团队成员跑测试时不用记命令,直接 ./run_tests.sh 就行。
9.7 常见问题与避坑
| 问题 | 原因 | 解决方法 |
|---|---|---|
| ctest 报 "No tests were found" | 忘记调用 enable_testing() | 在顶层 CMakeLists.txt 中添加 enable_testing() |
| 测试一直显示 "Not Run" | 测试可执行文件未编译 | 先运行 make 编译所有目标 |
| 测试路径不对 | CTest 工作目录问题 | 使用 WORKING_DIRECTORY 参数指定 |
我曾经在一个项目里遇到测试一直报「段错误」,排查了半天发现是测试代码里有个野指针。CTest 不会帮你检查代码质量,它只管跑。所以写测试用例时,该做的检查一个都不能少。
好了,CTest 入门就讲到这里。记住三个核心点:enable_testing() 开启测试、add_test() 注册用例、ctest 命令运行测试。把这三点吃透,CTest 的基本用法你就掌握了。