C++: 单元测试

最后更新:2026-08-26

第49课我们学了性能优化。

现在,我们要学习单元测试——保证代码质量的关键技能。

写了代码不测试,就像做了菜不尝味道。


1. 单元测试概述

(1) 1.1 什么是单元测试?

单元测试(Unit Test)是对最小可测试单元(函数、类)进行测试。

优势:


(2) 1.2 测试框架选择

框架 说明
Google Test Google出品,最流行
Catch2 单头文件,简单易用
Boost.Test Boost库的一部分
Doctest 类似Catch2,更快

推荐: Google Test(功能全)或 Catch2(简单)



2. Google Test入门

(1) 2.1 安装Google Test

Linux:

BASH
sudo apt-get install libgtest-dev

Windows: 用vcpkg或源码编译。


(2) 2.2 第一个测试

示例:用Google Test测试加法函数(难度⭐)

▶ 示例 2:代码示例(难度⭐)

CPP
#include <gtest/gtest.h>

int add(int a, int b) {
 return a + b;
}

TEST(AddTest, Positive) {
 EXPECT_EQ(add(2, 3), 5);
}

TEST(AddTest, Negative) {
 EXPECT_EQ(add(-2, -3), -5);
}

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

输出:

TEXT 📖 仅展示
[==========] Running 2 tests from 1 test suite.
[  PASSED  ] 2 tests.

运行结果:

TEXT 📖 仅展示
[==========] Running 2 tests from 1 test suite.
[ PASSED ] 2 tests.


3. 断言宏

(1) 3.1 ASSERT vs EXPECT

失败时的行为
ASSERT_* 终止当前测试
EXPECT_* 继续运行

推荐:EXPECT_*(能看到更多失败)


(2) 3.2 常用断言

断言 说明
EXPECT_EQ(a, b) a == b
EXPECT_NE(a, b) a != b
EXPECT_LT(a, b) a < b
EXPECT_GT(a, b) a > b
EXPECT_TRUE(cond) cond为真
EXPECT_FALSE(cond) cond为假
EXPECT_THROW(statement, exception_type) 期望抛出异常


4. 测试夹具(Test Fixture)

(1) 4.1 为什么需要夹具?

问题: 多个测试需要相同的初始化代码

解决方案: 测试夹具(继承 testing::Test


(2) 4.2 示例:用夹具测试队列(难度⭐⭐)

CPP
#include <gtest/gtest.h>
#include <queue>

class QueueTest : public testing::Test {
protected:
 void SetUp() override {
 q.push(1);
 q.push(2);
 q.push(3);
 }
 
 void TearDown() override {
 // 清理(如果需要)
 }
 
 std::queue<int> q;
};

TEST_F(QueueTest, Size) {
 EXPECT_EQ(q.size(), 3);
}

TEST_F(QueueTest, Front) {
 EXPECT_EQ(q.front(), 1);
}

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

输出:

TEXT 📖 仅展示
(程序输出)


5. 测试驱动开发(TDD)

(1) 5.1 什么是TDD?

TDD(Test-Driven Development)是指先写测试,再写代码

流程:

  1. 写测试(失败)
  2. 写代码(通过)
  3. 重构

(2) 5.2 示例:TDD开发栈(难度⭐⭐⭐)

CPP
// 1. 先写测试
TEST(StackTest, PushAndPop) {
 Stackint s;
 s.push(42);
 EXPECT_EQ(s.pop(), 42);
}

// 2. 再写代码
template<typename T>
class Stack {
 std::vectorT data;
public:
 void push(const T& x) { data.push_back(x); }
 T pop() { T x = data.back(); data.pop_back(); return x; }
};

输出:

TEXT 📖 仅展示
(程序输出)


6. 实战:测试学生类

▶ 示例 1:完整测试(难度⭐⭐⭐)

CPP
#include <gtest/gtest.h>
#include <string>

class Student {
 std::string name;
 int age;
 
public:
 Student(const std::string& name, int age) : name(name), age(age) {}
 
 std::string getName() const { return name; }
 int getAge() const { return age; }
};

TEST(StudentTest, Constructor) {
 Student s("张三", 20);
 EXPECT_EQ(s.getName(), "张三");
 EXPECT_EQ(s.getAge(), 20);
}

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

输出:

TEXT 📖 仅展示
(程序输出)

▶ 示例 3:简单的单元测试(难度⭐)

CPP
#include <iostream>
#include <cassert>

// 被测试的函数
int multiply(int a, int b) {
    return a * b;
}

bool isPositive(int n) {
    return n > 0;
}

int main() {
    // 测试 multiply
    assert(multiply(2, 3) == 6);
    assert(multiply(-2, 3) == -6);
    assert(multiply(0, 5) == 0);
    std::cout << "multiply 测试通过" << std::endl;

    // 测试 isPositive
    assert(isPositive(5) == true);
    assert(isPositive(-1) == false);
    assert(isPositive(0) == false);
    std::cout << "isPositive 测试通过" << std::endl;

    std::cout << "所有测试通过!" << std::endl;
    return 0;
}
▶ 试一试

输出:

TEXT 📖 仅展示
multiply 测试通过
isPositive 测试通过
所有测试通过!

❓ 常见问题

Q:单元测试能发现所有bug吗? A:不能。单元测试只能发现已知类型的错误。还需要集成测试、系统测试。


Q 测试代码要和产品代码一起发布吗?
A 不需要。测试代码通常只在开发时使用。

Q 怎么测试私有函数?
A - 方法1:测试公有接口(间接测试) - 方法2:用FRIEND_TEST暴露私有成员 - 方法3:重构,把私有函数提取到独立类

📖 小节

知识点 要点
单元测试 测试最小单元
Google Test 最流行的C++测试框架
断言宏 EXPECT_* 和 ASSERT_*
测试夹具 共享初始化代码
TDD 先写测试,再写代码

📝 作业

  1. **基础题 (Difficulty ⭐):写一个 add(a,b) 函数,用 Google Test 编写 3 个测试用例:正数相加、负数相加、零相加。

  2. **进阶题 (Difficulty ⭐⭐):写一个 isPalindrome 函数判断字符串是否为回文。编写至少 5 个测试用例覆盖正常/边界/特殊输入。

  3. **挑战题 (Difficulty ⭐⭐⭐):为一个"银行账户"类(含 deposit/withdraw/getBalance 方法)编写完整的单元测试。测试正常存取、透支拒绝、并发安全(如果有)。



下一课:实战:通讯录系统(#51)

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏