必须在且仅一个源文件中定义CATCH_CONFIG_MAIN后再包含catch.hpp,才能生成主函数;测试用例写在其他文件中并仅包含头文件,编译时一并链接。

怎么把Catch2单头文件加进项目里
Catch2 的 catch.hpp 确实是单头文件,但直接 #include "catch.hpp" 会编译失败——它默认只提供声明,不展开实现。必须在**一个且仅一个**源文件中定义 CATCH_CONFIG_MAIN 后再包含它,才能生成测试主函数。
常见错误是:多个 .cpp 都这么写,导致链接时 main 重复定义;或者完全没定义,报 undefined reference to 'main'。
推荐做法:
- 新建一个
test_main.cpp,内容只有两行:#define CATCH_CONFIG_MAIN #include "catch.hpp"
- 把你的测试用例写在其他
.cpp或.h里,统一#include "catch.hpp"(不用再定义宏) - 编译时把
test_main.cpp和所有测试文件一起传给编译器
如何写一个最简可运行的 TEST_CASE
不需要类、不需要 fixture、不需要额外配置——TEST_CASE 就是顶层作用域的普通函数,被 Catch2 自动注册和调用。
注意点:
- 测试名必须是字符串字面量,比如
TEST_CASE("addition works"),不能是变量或宏拼接 - 内部用
REQUIRE(失败立即终止)或CHECK(失败继续执行)做断言,别用assert() - 所有测试代码都在这个宏展开的作用域内,局部变量无需特殊管理
示例:
TEST_CASE("vector size after push_back") {
std::vector<int> v;
v.push_back(42);
REQUIRE(v.size() == 1);
CHECK(v[0] == 42);
}</int>
为什么运行测试时没输出或卡住
默认行为是运行所有测试并输出简要结果(成功/失败数),但不会打印每条 REQUIRE 的详细路径或变量值——这常被误认为“没运行”或“卡死”。
调试建议:
- 加
-s参数查看每个测试的名称和耗时:./test_exe -s - 加
-r xml或-r junit输出结构化结果,方便 CI 解析 - 遇到崩溃,用
-d启用调试输出,会显示断言失败时的完整表达式和左右值 - 如果测试本身有死循环或阻塞 IO,Catch2 不会干预——它只管调用和计时
如何让测试代码不污染生产构建
测试文件不该出现在最终可执行文件或库中。最稳妥的方式是**分离构建目标**,而不是靠预处理宏开关。
典型做法:
- 测试源码放在
tests/目录下,与src/物理隔离 - CMake 中用
add_executable(test_exe ...)单独构建测试程序,不参与target_link_libraries(app ...) - 避免在生产代码里写
#ifdef TEST包裹测试逻辑——这会让头文件变重,还容易漏删 - 如果必须共用某些工具函数,把它们抽到
test_utils.hpp,只在测试目标中链接
单头文件轻量,但组织方式决定它是否真的“轻”——文件少不等于结构松散。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











