C++ Catch2
外观
C++ Catch2 单元测试框架[编辑 | 编辑源代码]
简介[编辑 | 编辑源代码]
Catch2 是一个现代、轻量级的 C++ 单元测试框架,以其简洁的语法和强大的功能著称。它采用纯头文件设计,无需预编译,支持 BDD(行为驱动开发)风格和传统单元测试风格,是 C++11 及以上版本项目的理想测试工具。
主要特点:
- 零外部依赖,仅需单个头文件
- 测试用例自动注册
- 支持标签化测试组织和过滤
- 提供丰富的断言宏
- 可输出多种格式的测试报告
安装与配置[编辑 | 编辑源代码]
获取 Catch2[编辑 | 编辑源代码]
从 GitHub 下载最新版本的 catch.hpp
,或通过包管理器安装:
# 使用 vcpkg
vcpkg install catch2
# 使用 conan
conan install catch2/2.13.7
基本项目集成[编辑 | 编辑源代码]
最简单的使用方式是将 catch.hpp
包含到测试文件中:
#define CATCH_CONFIG_MAIN // 生成 main()
#include "catch.hpp"
核心概念[编辑 | 编辑源代码]
测试用例[编辑 | 编辑源代码]
基本测试用例结构:
TEST_CASE("测试描述", "[标签1][标签2]") {
// 测试代码
REQUIRE(expression); // 断言
}
断言宏[编辑 | 编辑源代码]
Catch2 提供多种断言风格:
类型 | 宏 | 说明 | 要求断言 | REQUIRE(expr) |
失败时终止测试用例 | 检查断言 | CHECK(expr) |
失败时继续执行 | 浮点比较 | REQUIRE(1.0 == Approx(0.999).epsilon(0.01)) |
带容差的浮点比较 | 异常检查 | REQUIRE_THROWS(expr) |
验证是否抛出异常 |
---|
实际示例[编辑 | 编辑源代码]
示例1:字符串处理测试[编辑 | 编辑源代码]
测试字符串反转函数:
#include <string>
#include <algorithm>
std::string reverse_string(const std::string& str) {
std::string result(str);
std::reverse(result.begin(), result.end());
return result;
}
TEST_CASE("字符串反转", "[string][algorithm]") {
SECTION("基本反转") {
REQUIRE(reverse_string("hello") == "olleh");
REQUIRE(reverse_string("") == "");
}
SECTION("Unicode支持") {
REQUIRE(reverse_string("こんにちは") == "はちにんこ");
}
}
输出示例:
All tests passed (4 assertions in 2 test cases)
示例2:数学运算测试[编辑 | 编辑源代码]
测试阶乘函数:
unsigned int factorial(unsigned int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
TEST_CASE("阶乘计算", "[math][recursion]") {
REQUIRE(factorial(0) == 1);
REQUIRE(factorial(1) == 1);
REQUIRE(factorial(5) == 120);
REQUIRE(factorial(10) == 3628800);
}
高级特性[编辑 | 编辑源代码]
参数化测试[编辑 | 编辑源代码]
使用 GENERATE
创建数据驱动测试:
TEST_CASE("参数化测试示例", "[generators]") {
auto x = GENERATE(1, 2, 3, 5, 7);
SECTION("测试素数") {
REQUIRE(is_prime(x));
}
}
BDD 风格[编辑 | 编辑源代码]
行为驱动开发风格:
SCENARIO("银行账户操作", "[account][bdd]") {
GIVEN("一个新账户") {
Account account(100);
WHEN("存入50元") {
account.deposit(50);
THEN("余额正确") {
REQUIRE(account.balance() == 150);
}
}
}
}
测试夹具[编辑 | 编辑源代码]
共享测试设置:
class DatabaseFixture {
protected:
Database db;
public:
DatabaseFixture() : db("test.db") { db.connect(); }
~DatabaseFixture() { db.disconnect(); }
};
TEST_CASE_METHOD(DatabaseFixture, "数据库查询", "[database]") {
REQUIRE(db.query("SELECT * FROM users").size() > 0);
}
测试组织与执行[编辑 | 编辑源代码]
标签系统[编辑 | 编辑源代码]
Catch2 的标签可以用于过滤测试:
执行特定标签的测试:
./tests [math] # 只运行数学相关测试 ./tests ~[database] # 排除数据库测试
测试报告[编辑 | 编辑源代码]
支持多种格式输出:
- 控制台 (默认)
- JUnit 格式 (CI 集成)
- XML 格式
- TAP 格式
最佳实践[编辑 | 编辑源代码]
1. 保持测试独立,不依赖执行顺序
2. 为每个测试用例使用描述性名称
3. 合理使用 SECTION 组织相关断言
4. 将慢速测试标记为 [!slow]
5. 定期运行测试,最好集成到构建流程中
常见问题[编辑 | 编辑源代码]
测试未执行[编辑 | 编辑源代码]
可能原因:
- 未定义
CATCH_CONFIG_MAIN
- 测试被标签过滤排除
- 测试代码未被编译
浮点比较问题[编辑 | 编辑源代码]
正确方式:
REQUIRE(1.0/3.0 == Approx(0.333333).epsilon(0.0001));
性能考量[编辑 | 编辑源代码]
Catch2 的编译时开销较大,建议:
- 将测试实现与声明分离
- 使用预编译头
- 在大型项目中考虑拆分测试二进制文件
与其他框架比较[编辑 | 编辑源代码]
特性 | Catch2 | Google Test | Boost.Test | 头文件方式 | ✔️ | ❌ | ❌ | BDD 支持 | ✔️ | ❌ | ✔️ | 标签系统 | ✔️ | ❌ | ✔️ | 断言数量 | 中等 | 多 | 多 | 学习曲线 | 低 | 中 | 高 |
---|
延伸学习[编辑 | 编辑源代码]
- 测试驱动开发(TDD)方法论
- 模拟对象(Mock)技术
- 代码覆盖率工具
- 持续集成中的测试集成