跳转到内容

C++ Catch2

来自代码酷
Admin留言 | 贡献2025年4月28日 (一) 21:27的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

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 的标签可以用于过滤测试:

graph TD A[所有测试] --> B[核心功能] A --> C[性能测试] A --> D[数据库测试] B --> E[字符串处理] B --> F[数学运算]

执行特定标签的测试:

./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)技术
  • 代码覆盖率工具
  • 持续集成中的测试集成