22、Boost.Test集成:find_package(Boost)、BOOST_TEST_MODULE、BOOST_AUTO_TEST_SUITE
Boost.Test 是我个人在 C++ 项目中用得最久的测试框架之一。说实话,它不像 Google Test 那么轻量,但胜在功能全面、与 Boost 生态无缝衔接。今天我们就聊聊怎么在 CMake 里把它集成进来,以及几个最常用的宏。
22.1 用 find_package 找到 Boost
集成 Boost.Test 的第一步,就是让 CMake 找到 Boost 库。这活儿 find_package 就能干。
find_package(Boost REQUIRED COMPONENTS unit_test_framework)
这里有个坑——unit_test_framework 是 Boost.Test 的组件名,别写错了。我以前就犯过这种低级错误,把名字写成了 test,结果 CMake 报错说找不到,折腾了半天才发现是名字不对。
找到之后,链接到你的测试目标:
add_executable(my_test test_main.cpp)
target_link_libraries(my_test PRIVATE Boost::unit_test_framework)
嗯,这里要注意:Boost::unit_test_framework 是 CMake 的导入目标写法,比直接写 ${Boost_LIBRARIES} 更现代、更安全。我建议你养成用导入目标的习惯。
核心要点:
- 必须指定
COMPONENTS unit_test_framework - 链接时用
Boost::unit_test_framework - 如果 Boost 安装在非标准路径,需要设置
BOOST_ROOT或Boost_DIR
22.2 BOOST_TEST_MODULE:定义测试模块
这个宏是 Boost.Test 的入口。你只需要在任意一个源文件中定义它,Boost.Test 就会自动生成 main() 函数。
#define BOOST_TEST_MODULE MyTestModule
#include <boost/test/unit_test.hpp>
就这么两行,测试框架就搭好了。你想想看,省了多少样板代码?
不过有个细节:BOOST_TEST_MODULE 必须在 #include <boost/test/unit_test.hpp> 之前定义。顺序错了,编译器会报一堆莫名其妙的错误。我当年第一次用的时候就被坑过,编译错误铺天盖地,还以为自己代码写错了。
小技巧:如果你需要自定义 main() 函数(比如初始化某些全局资源),可以定义 BOOST_TEST_NO_MAIN,然后自己写 main() 并调用 boost::unit_test::unit_test_main()。
22.3 BOOST_AUTO_TEST_SUITE:组织测试用例
当测试用例多了以后,你得把它们分门别类。Boost.Test 提供了 BOOST_AUTO_TEST_SUITE 和 BOOST_AUTO_TEST_SUITE_END 来创建测试套件。
#define BOOST_TEST_MODULE MathTests
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(AdditionTests)
BOOST_AUTO_TEST_CASE(test_positive_numbers) {
BOOST_CHECK_EQUAL(1 + 1, 2);
BOOST_CHECK_EQUAL(2 + 3, 5);
}
BOOST_AUTO_TEST_CASE(test_negative_numbers) {
BOOST_CHECK_EQUAL(-1 + -1, -2);
BOOST_CHECK_EQUAL(-5 + 3, -2);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(SubtractionTests)
BOOST_AUTO_TEST_CASE(test_basic) {
BOOST_CHECK_EQUAL(5 - 3, 2);
BOOST_CHECK_EQUAL(10 - 7, 3);
}
BOOST_AUTO_TEST_SUITE_END()
套件可以嵌套,比如:
BOOST_AUTO_TEST_SUITE(MathTests)
BOOST_AUTO_TEST_SUITE(AdditionTests)
// 测试用例
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(SubtractionTests)
// 测试用例
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
嵌套套件在大型项目中特别有用。我记得在一个金融交易系统的测试里,我们用了三层嵌套:交易引擎测试 > 订单匹配测试 > 限价单测试。这样跑测试时,输出结果一目了然,哪个模块出了问题一眼就能看出来。
注意:套件名称不要重复。如果两个套件同名,Boost.Test 会合并它们的内容,这可能导致测试顺序混乱。我曾经因为这个 bug 排查了一下午,最后发现是两个文件里定义了同名的套件。
22.4 完整的 CMake 集成示例
把上面这些串起来,一个完整的 CMakeLists.txt 长这样:
cmake_minimum_required(VERSION 3.14)
project(BoostTestDemo LANGUAGES CXX)
find_package(Boost REQUIRED COMPONENTS unit_test_framework)
add_executable(test_math test_math.cpp)
target_link_libraries(test_math PRIVATE Boost::unit_test_framework)
# 启用 CTest
enable_testing()
add_test(NAME MathTests COMMAND test_math)
然后你就可以用 ctest 来跑了:
$ cmake -B build
$ cmake --build build
$ ctest --test-dir build
22.5 知识体系图
下面这张图帮你理清 Boost.Test 集成的核心流程:
22.6 常见问题与避坑
- 链接错误:如果遇到
undefined reference to boost::unit_test::...,八成是没链接Boost::unit_test_framework。检查一下target_link_libraries有没有写对。 - 编译错误:
BOOST_TEST_MODULE未定义?看看是不是 include 顺序错了。这个宏必须在#include <boost/test/unit_test.hpp>之前。 - 运行时崩溃:如果测试程序一跑就崩,可能是 Boost 版本与编译器不兼容。我建议用 Boost 1.70 以上版本,配合 GCC 8+ 或 Clang 10+。
我的习惯:在项目的 cmake/ 目录下放一个 FindBoost.cmake 的备用脚本。这样即使系统没装 Boost,也能通过 FetchContent 自动下载。说白了,就是让构建过程更鲁棒。
Boost.Test 的集成其实不复杂,核心就是三步:找到库、链接库、定义测试模块。套件机制帮你把测试组织得井井有条。下次我们聊聊更高级的用法——参数化测试和 fixture。
公众号:蓝海资料掘金营,微信deep3321