C++ 测试:框架与工具概览(Google Test、Catch2、doctest)

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C++测试:框架与工具



高质量测试是C++开发中不可或缺的一部分。与动态语言不同,C++需要特别关注内存管理、对象生命周期和性能。本文将介绍三种最流行的单元测试框架:Google Test、Catch2和doctest,并涉及一些辅助工具。



为什么C++需要测试?

C++是一种手动管理内存并拥有强大模板机制的语言。没有测试,很容易出现:

  • 内存泄漏和重复释放
  • 指针操作中的未定义行为 (UB)
  • 运算符重载和拷贝构造函数中的错误
  • 重构遗留代码时的回归问题

测试框架可以自动化验证过程,帮助快速定位问题。



Google Test (gtest)

来自Google的最流行框架。支持所有主要功能:ASSERT_*和EXPECT_*宏、参数化测试、测试夹具 (test fixtures)、死亡测试。



安装(通过CMake FetchContent)

include(FetchContent)FetchContent_Declare(  googletest  GIT_REPOSITORY https://github.com/google/googletest.git  GIT_TAG release-1.14.0)FetchContent_MakeAvailable(googletest)


简单测试示例

#include <gtest/gtest.h>

int factorial(int n) { return (n <= 1) ? 1 : n * factorial(n - 1);}

TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(factorial(0), 1);}

TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(factorial(5), 120); EXPECT_EQ(factorial(3), 6);}

int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();}


测试夹具和参数化测试

class MathFixture : public ::testing::Test {protected:    void SetUp() override { /* 初始化 */ }    void TearDown() override { /* 清理 */ }};

// 参数化测试class SumTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};TEST_P(SumTest, CheckSum) { auto [a, b, expected] = GetParam(); EXPECT_EQ(a + b, expected);}INSTANTIATE_TEST_SUITE_P(SumParams, SumTest, ::testing::Values( std::make_tuple(1, 1, 2), std::make_tuple(0, 0, 0) ));


优点:庞大的社区、与CI/CD集成、强大的宏、支持死亡测试。
缺点:编译相对较慢、可执行文件体积较大。



Catch2

现代化的框架,注重测试的可读性。采用BDD风格(行为驱动开发)并支持节 (sections)。



安装(header-only)

Catch2以单个头文件形式分发。只需下载catch_amalgamated.hpp并包含它即可。



使用节的示例

#define CATCH_CONFIG_MAIN#include <catch2/catch.hpp>

int divide(int a, int b) { if (b == 0) throw std::invalid_argument("division by zero"); return a / b;}

TEST_CASE("Division tests", "[math]") { SECTION("Normal division") { REQUIRE(divide(10, 2) == 5); } SECTION("Division by zero") { REQUIRE_THROWS_AS(divide(5, 0), std::invalid_argument); }}


BDD风格(Given-When-Then)

SCENARIO("Vector push_back operation", "[container]") {    GIVEN("An empty vector") {        std::vector<int> v;        WHEN("We push one element") {            v.push_back(42);            THEN("The size becomes 1") {                REQUIRE(v.size() == 1);            }            AND_THEN("The element is correct") {                REQUIRE(v[0] == 42);                    

推荐