C 和 C++ 测试是可执行程序,其状态必须影响构建和 CI 结果。测试框架可以改进断言和报告,但当测试可执行文件拥有专用的 main 以及确定性的依赖,并且已集成到项目测试运行器中时,这些条件就足够了。
将测试构建为一等目标 #
将测试目标与生产二进制文件分开编译,并将它们链接到生产库。向现有测试运行器(例如 CTest、Meson 或 Automake 的 TESTS)注册每个可执行文件,使非零退出状态导致 CI 失败。
cmake
add_executable(parser_test parser_test.cc)
target_link_libraries(parser_test PRIVATE parser)
add_test(NAME parser COMMAND parser_test)尽可能将仅供测试使用的 fixture 和 fake 放在生产接口之外。测试运行器应报告失败用例,保留诊断信息,并在任何必要断言或进程失败时返回非零值。
测试可观察行为 #
测试公开行为、错误报告、清理和边界条件,而不是私有表示。按范围组织覆盖:
- 单元测试使用受控协作者来测试小型组件。
- 集成测试验证真实组件之间的边界,例如序列化、数据库适配器,或解析器与扫描器。
- 端到端测试验证组装后的可执行文件或服务契约。
应包含空输入、限制、无效编码、可注入的分配或 I/O 失败、所有权转换,以及针对过去已修复缺陷的回归测试。测试应断言承诺的结果,而不是偶然的实现细节。
使依赖具有确定性 #
注入或包装时钟、随机性、文件系统、子进程和网络客户端。记录失败的随机种子,并使其可重放。使用由测试工具控制的临时测试工作区、唯一端口或内存传输,以及有界超时。避免共享环境状态和测试顺序依赖。
在子进程中运行具有破坏性或容易崩溃的测试。进程隔离还允许直接断言退出状态、信号、标准输出、标准错误和命令行行为。
结合测试使用运行时诊断 #
Sanitizer 只能在已执行路径上发现某些类别的缺陷,因此它们是对功能测试的补充,而不是替代。
bash
c++ -fsanitize=address,undefined -fno-omit-frame-pointer -g \
parser_test.cc -o parser_test
./parser_testAddressSanitizer 可以检测许多无效内存访问;UndefinedBehaviorSanitizer 可以诊断选定的未定义操作。在 CI 中启用项目支持的 sanitizer 配置,保留带符号化的栈和日志,并将 sanitizer 报告视为测试失败。
评论
在 GitHub 上阅读或评论(发表评论需要登录)