基于CMake、Catch2与CTest的多文件回归测试优化需求问询
针对你的回归测试优化方案
结合Catch2和CMake的特性,直接解决你提出的四个目标:
1. 单次初始化 + 并行测试文件
全局单次初始化
用Catch2的全局初始化机制,确保do_some_setup()只在整个测试进程启动时执行一次:
#include <Catch2/catch_all.hpp> CATCH_CONFIG_GLOBAL_INITIALIZER(GlobalServerSetup) { // 静态变量保证初始化一次 static auto const global_state = do_some_setup(); // 提供全局访问接口 [[nodiscard]] auto get_server_state() -> decltype(global_state) const& { return global_state; } }
并行执行文件测试
把每个测试文件转为独立的TEST_CASE,Catch2 3.x+支持并行运行多个TEST_CASE,只需编译时启用并行支持,运行时指定线程数即可。
2. 失败后继续执行
只要每个文件对应独立的TEST_CASE,Catch2默认会继续运行其他测试用例——哪怕某个用例抛出异常失败,也只会标记该用例为失败,不会终止整个测试流程,完全不需要手动加try-catch。
3. 单独运行指定文件
当每个文件对应独立的TEST_CASE时,你可以通过两种方式单独运行:
- 直接调用测试程序,指定测试用例名称:
./server_type_regressions "Regression: test_files/xxx.msg" - 用CTest的匹配参数筛选:
ctest -R "Regression: test_files/xxx.msg"
4. 自动检测测试文件
用CMake自动扫描测试文件,并生成对应的Catch2测试用例代码,完全不用手动维护文件列表。在CMakeLists.txt中添加以下逻辑:
# 扫描指定目录下的所有测试文件(比如.msg后缀) file(GLOB_RECURSE REGRESSION_TEST_FILES "${PROJECT_SOURCE_DIR}/test_files/*.msg") # 生成自动测试代码文件 set(REGRESSION_TEST_SRC "${CMAKE_CURRENT_BINARY_DIR}/auto_gen_regression_tests.cpp") file(WRITE ${REGRESSION_TEST_SRC} "#include <Catch2/catch_all.hpp>\n#include \"your_state_header.hpp\"\n") # 为每个文件生成独立的TEST_CASE foreach(TEST_FILE ${REGRESSION_TEST_FILES}) # 获取文件相对路径作为测试用例名称 file(RELATIVE_PATH TEST_NAME ${PROJECT_SOURCE_DIR} ${TEST_FILE}) # 转义字符串中的特殊字符,避免C++编译错误 string(REPLACE "\"" "\\\"" ESCAPED_TEST_NAME ${TEST_NAME}) string(REPLACE "\\" "\\\\" ESCAPED_TEST_NAME ${ESCAPED_TEST_NAME}) string(REPLACE "/" "\\/" ESCAPED_TEST_NAME ${ESCAPED_TEST_NAME}) file(APPEND ${REGRESSION_TEST_SRC} " TEST_CASE(\"Regression: ${ESCAPED_TEST_NAME}\", \"[regression][server_type]\") { auto const& state = get_server_state(); INFO(\"Testing file: ${ESCAPED_TEST_NAME}\"); auto parser = state.make_parser(\"${TEST_FILE}\"); for (auto const& message : parser) { INFO(\"Processing message: \" << message); handle(message); } } ") endforeach() # 添加测试可执行文件 add_executable(server_type_regressions server_regression_main.cpp ${REGRESSION_TEST_SRC} ) target_link_libraries(server_type_regressions PRIVATE Catch2::Catch2 your_app_library) # 启用Catch2并行支持 target_compile_definitions(server_type_regressions PRIVATE CATCH_CONFIG_PARALLELIZE) # 注册到CTest catch_discover_tests(server_type_regressions)
运行并行测试
启动测试时,指定并行线程数:
# 直接运行测试程序 ./server_type_regressions --parallel --jobs 4 # 或者用CTest ctest -j 4
替代简化方案(无需生成代码)
如果不想用CMake生成代码,可以用Catch2的GENERATE宏动态生成子用例,结合静态变量实现单次初始化:
#include <Catch2/catch_all.hpp> #include <vector> #include <sstream> // 通过CMake传递的文件列表(在CMake中定义编译宏) constexpr auto REGRESSION_FILE_LIST = REGRESSION_FILES; std::vector<std::string> get_test_files() { std::vector<std::string> files; std::stringstream ss(REGRESSION_FILE_LIST); std::string path; while (ss >> path) { files.emplace_back(std::move(path)); } return files; } TEST_CASE("server type regressions", "[server_type][regression]") { // 静态变量确保初始化一次 static auto const state = do_some_setup(); // 为每个文件生成子用例 auto const file_path = GENERATE(from_range(get_test_files())); INFO("Testing file: " << file_path); auto parser = state.make_parser(file_path); for (auto const& message : parser) { INFO("Processing message: " << message); handle(message); } }
对应的CMake配置:
file(GLOB_RECURSE REGRESSION_TEST_FILES "${PROJECT_SOURCE_DIR}/test_files/*.msg") # 把文件列表转为空格分隔的字符串,通过编译宏传递 string(JOIN " " FILE_LIST_STR ${REGRESSION_TEST_FILES}) target_compile_definitions(server_type_regressions PRIVATE "REGRESSION_FILES=\"${FILE_LIST_STR}\"") target_compile_definitions(server_type_regressions PRIVATE CATCH_CONFIG_PARALLELIZE) catch_discover_tests(server_type_regressions)
这种方式代码更简洁,但子用例是父TEST_CASE的一部分,单独运行时需要匹配更具体的名称,比如:
./server_type_regressions "server type regressions" -c "file_path=test_files/xxx.msg"
内容的提问来源于stack exchange,提问作者David Stone
相关产品推荐
相关产品推荐

