Catch2
培育能力的事必须继续不断地去做,又必须随时改善学习方法,提高学习效率,才会成功。——叶圣陶
https://github.com/catchorg/Catch2
Catch2:让 C++ 测试写起来更像在写 C++ 本身
测试框架这件事,说到底是为了帮开发者把“我想验证什么”表达得更自然。如果一个测试框架本身写起来就拧巴,那么测试代码很快也会变成另一种负担。Catch2 给人的第一印象,恰恰是它想把这件事变简单。
根据仓库 description,Catch2 是一个现代的、C++ 原生的测试框架,面向 unit-tests、TDD 和 BDD,支持 C++14、C++17 以及更高版本。README 则进一步说明,Catch2 主要是一个 C++ 单元测试框架,同时也提供 基础的微基准测试能力,以及 简单的 BDD 宏。
这是一种很清晰的定位:它首先是测试框架,但又不只停留在最基础的断言层面。它希望把单元测试、测试驱动开发、行为驱动风格,以及一部分性能测量能力,尽量放进同一个自然的 C++ 语境里。
项目地址:https://github.com/catchorg/Catch2
Catch2 想解决的,不只是“能不能测”,而是“写起来顺不顺”
README 对 Catch2 的优势总结得非常直接:使用起来简单而自然。
它提到了几个很能说明气质的点:
- 测试名称不必是合法标识符
- 断言看起来像普通的 C++ 布尔表达式
- sections 提供了一种优雅而局部的方式共享测试中的 set-up 和 tear-down 代码
这些话放在一起,其实已经很接近 Catch2 的核心魅力了。
很多测试框架的使用成本,不一定来自功能缺失,而是来自表达方式太生硬。测试名字受限、断言语法绕、公共准备代码散得到处都是,最后明明只是想验证一个函数,却像在和框架语法较劲。Catch2 明显不想让这种情况发生,它更希望测试代码读起来像是在正常地写 C++,而不是先学一层额外腔调。
一个简单的单元测试例子,就能看出它的风格
README 给出了一段非常经典的示例:用阶乘函数来写单元测试。
1 |
|
这段代码之所以好懂,不是因为示例足够简单,而是因为 Catch2 的测试写法本身就很直白。
TEST_CASE 直接表达测试主题,REQUIRE 则像在大声说:“这里必须成立。”
你不需要绕进复杂的断言结构里,也不需要给测试名强行套进某种僵硬标识符规范中。测试标题可以是自然语言,断言也几乎就是普通布尔判断的形状。
对于 C++ 开发者来说,这种“顺着语言本身来”的感觉,往往比功能表里多几个开关更重要。
它不只测正确性,也愿意碰一点性能
Catch2 的 README 明确说明,它还提供 basic micro-benchmarking features。这意味着它不仅关心“结果是不是对”,也给了开发者一个轻量入口,去观察某段代码在微观层面的运行表现。
README 中的 Fibonacci 示例就把这一点表现得很直接:
1 |
|
这个示例很有意思,因为它没有把 benchmark 和 correctness 完全割裂开。
它先用 REQUIRE 验证结果,再用 BENCHMARK 对指定计算做微基准测试。这样的写法让“先确认逻辑,再观察表现”变成一条很顺的路径。
README 还特别提醒:benchmark 默认不会运行,需要通过 [!benchmark] 标签显式执行。
这个细节也很重要。它说明 Catch2 对测试场景是有区分的,不会把基准测试默认塞进每次常规执行里,而是让它以更明确的方式存在。
BDD 不是口号,README 里已经把它放进定位中
仓库 description 中明确提到 Catch2 面向 TDD 和 BDD,README 也说它提供 simple BDD macros。
虽然当前 README 首页没有展开 BDD 宏的具体语法,但仅从定位上看,Catch2 并没有把自己局限在“只会写普通断言式单元测试”的框架形象里。它承认开发者在测试表达上会有不同偏好,也把行为驱动风格纳入了自身能力范围。
这使得 Catch2 的测试表达空间更宽一些。
有的人喜欢简洁、直接、函数级的断言;有的人更希望测试描述和行为语义更强。Catch2 在项目介绍中已经表明,它愿意为这两种使用习惯同时腾位置。
Catch2 v3 的变化,是一次很重要的转身
README 里有一段很关键的信息:Catch2 v3 has been released。
而且 README 明确说明,你当前所在的是 devel 分支,这里是 v3 的开发分支。仓库 metadata 也显示,这个仓库的默认分支正是 devel。
更重要的是,README 把 v3 的一个大变化说得非常直白:
Catch2 is no longer a single-header library.
Catch2 now behaves as a normal library, with multiple headers and separately compiled implementation.
这是个相当鲜明的转折点。
过去很多人提到 Catch,往往会立刻想到“单头文件测试框架”这种印象。但在 v3 里,README 已经明确表示,Catch2 不再是单头文件库,而是更像一个普通库那样工作:有多个头文件,也有单独编译的实现部分。
这不是一句轻描淡写的更新说明,而是一次对使用形态的重新界定。它意味着 Catch2 在架构和集成方式上,已经与早期的“单头文件”印象拉开了距离。
README 还提到,文档正在逐步更新以适应这些变化,这项工作仍在进行中。
同时,对于从 v2 迁移到 v3 的用户,README 也明确给出方向:可以查看迁移文档,其中包含上手指引和常见迁移问题汇总。
另外,如果你需要之前的大版本,README 也指出可以查看 GitHub 上的 v2.x 分支。
这一段信息整体上给人的感觉很坦率:版本确实发生了大变化,项目也没有试图掩饰这件事,而是把变化、迁移方向和旧版本入口都摆在前面。
“自然”这件事,在测试名字和断言里体现得很明显
README 里有一句很值得反复品味的话:test names do not have to be valid identifiers。
这件事看似不大,实际上非常影响测试可读性。
因为一旦测试名不再被“变量命名规则”束缚,测试代码就更容易直接表达意图。你可以把测试标题写成真正面向人的语句,而不是被迫挤成某种技术化缩写。测试一旦可读,就更容易成为文档的一部分,而不只是执行器勉强能识别的符号集合。
再加上 README 提到的另一点:assertions look like normal C++ boolean expressions。
这意味着 Catch2 在语法层面努力减少“框架腔”,让你更专注于条件本身,而不是测试 DSL 的绕法。
这种体验上的减负,往往是一个测试框架能不能长期留下来的关键。
sections 这一点,也很像是为真实测试场景准备的
README 提到,sections provide a nice and local way to share set-up and tear-down code in tests。
虽然首页没有展开具体代码示例,但这句话已经传递出一个很清楚的方向:Catch2 关心的不只是“能不能断言”,也关心测试组织结构是否容易维护。
在实际测试中,最容易让人头疼的往往不是断言本身,而是准备逻辑和清理逻辑如何安排。如果共享代码写得太远,测试就会失去局部性;如果每段测试都完全重复,又很快会变得笨重。README 把 sections 单独拿出来说,说明它在 Catch2 里的位置并不边缘,而是“自然测试组织方式”的一部分。
Catch2 的文档结构很朴素,但方向很明确
README 在 “How to use it” 一节里,把文档分成了三部分:
- 为什么还需要另一个 C++ 测试框架
- Tutorial
- Reference section
这种结构其实很讨喜,因为它分别对应三种完全不同的阅读需求:
- 想先理解理念的人
- 想快速开始的人
- 想查细节的人
一个测试框架的文档如果只有 API 列表,通常不够友好;如果只有宣传性介绍,也不够落地。Catch2 在 README 里至少把入口分层做得很清楚,让人知道自己该从哪儿开始。
从仓库 description 看,它的语言边界也讲得很明白
仓库 description 里除了说它是现代的 C++ 原生测试框架,还明确给出了标准支持范围:
- 使用 C++14、C++17 及更高版本
- C++11 支持在
v2.x分支 - C++03 支持在 Catch1.x 分支
这段信息很有分寸感。它没有模糊地说“支持各种 C++ 版本”,而是把不同标准支持与不同分支的关系说清楚。这样一来,读者能更明确地知道自己应该关注哪个版本线。
同时,这种说明也和 README 中关于 v3、v2.x 的版本分层形成了呼应:Catch2 不是把所有历史兼容性都混成一团,而是通过不同分支来承载不同阶段的能力边界。
它的身份非常纯粹:测试框架,但不是单薄的测试框架
如果只看第一眼,Catch2 像是一个“写单元测试的库”。
但 README 和 description 拼在一起后,会发现它的定位其实更完整一些:
- 它是 C++ 的单元测试框架
- 它面向 TDD
- 它支持简单的 BDD 宏
- 它提供基础的微基准测试能力
- 它强调测试写法的自然性
- 它通过 sections 改善测试中的局部组织方式
这种组合很有意思。它没有把自己包装成包治百病的大而全平台,而是在测试这条主线上,尽可能把几类高频需求组织到一起:正确性验证、行为表达、性能观察、测试结构组织。
这会让它显得“专注”,但并不“单薄”。
默认分支是 devel,这件事本身也透露出项目节奏
根据仓库信息,Catch2 的默认分支是 devel。README 也明确写着:你所在的是 devel 分支,v3 正在这里开发。
这会带来一种很直观的项目印象:Catch2 的主仓库展示的是一个持续演进中的主线,而不是把默认入口固定在某个只讲历史的稳定快照上。README 也坦诚地提到,文档还在慢慢更新以覆盖 v3 带来的变化。
这种表达方式并不花哨,但很真实。它像是在告诉使用者:这个项目在往前走,而且它愿意把变化直接展示出来。
从语言构成和仓库信息看,它有非常明确的“C++ 原生气质”
仓库信息显示,Catch2 的主要语言是 C++。
这一点几乎不用多解释,因为整个项目介绍都围绕 “C++-native” 展开。
许可证方面,仓库使用的是 Boost Software License 1.0。默认分支为 devel,项目长期围绕 C++ 测试框架这一核心方向展开。再加上 README 中的示例代码和文档组织方式,这个仓库给人的整体印象很一致:没有刻意绕去别处,它就是认真在做 C++ 测试体验这件事。
如果把 Catch2 拟人化一点来看
Catch2 很像那种说话不多,但特别懂开发者别扭点的工具。
它不会先端上一套冗长仪式,而是先告诉你:“来,直接写测试吧,而且尽量按你熟悉的 C++ 方式写。”
它不强迫测试名变成拧巴的标识符,不把断言弄成另一门小语言,也不把微基准测试排除在门外。它像是在测试代码和 C++ 代码之间,悄悄拆掉了几堵本来不必要的墙。
结语
Catch2 的吸引力,不在于它把自己说得多复杂,而在于它把“测试应该自然”这件事贯彻得很明确。README 用很短的篇幅就讲清了它的几个核心点:单元测试是主场,微基准测试和简单 BDD 宏是补充;测试名称更自由,断言更像普通 C++ 表达式,sections 则帮助组织测试结构。
而 v3 的发布,又让这个项目从“单头文件时代的经典印象”继续迈向更像常规库的使用形态。它在变化,但仍然保留着最让人记住的那个气质:让 C++ 测试尽量回到 C++ 本身的语言感觉里。
