C++测试:单元测试、集成测试和端到端测试(附示例)

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

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

开始课程

引言:为什么测试对 C++ 项目至关重要



测试 C++ 代码不仅仅是一种形式,更是一种确保软件稳定性、安全性和可维护性的基本实践。与解释型语言不同,在解释型语言中错误可能立即显现,而在 C++ 中,bug 通常只有在编译或特定条件下执行时才会暴露。被忽略的内存泄漏、未定义行为或错误的指针处理都可能导致致命崩溃。



现代软件开发行业区分了三个主要的测试层级:单元测试、集成测试和端到端测试。每个层级解决其自身的任务,它们共同构成了“测试金字塔”,能够在发布到生产环境前捕获多达 90% 的错误。



在本文中,我们将使用流行的框架 Google Test 和 Catch2,通过 C++ 的实际示例来详细讲解每种测试类型,并讨论其最佳实践。



1. 单元测试:检查原子模块



单元测试是最底层、最快的测试层级。它们独立于系统其余部分,检查单个函数、类或方法。目标是确保每个代码的“构件块”都能正确工作。



使用 Google Test 的单元测试示例



考虑一个简单的数学函数:



// math_utils.h#pragma once

namespace MathUtils { int add(int a, int b); int divide(int a, int b);}


// math_utils.cpp#include "math_utils.h"

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

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


现在让我们使用 Google Test 编写单元测试:



// test_math_utils.cpp#include <gtest/gtest.h>#include "math_utils.h"

TEST(MathUtilsTest, AddPositiveNumbers) { EXPECT_EQ(MathUtils::add(2, 3), 5); EXPECT_EQ(MathUtils::add(0, 0), 0);}

TEST(MathUtilsTest, AddNegativeNumbers) { EXPECT_EQ(MathUtils::add(-1, -1), -2); EXPECT_EQ(MathUtils::add(-5, 3), -2);}

TEST(MathUtilsTest, DivideNormal) { EXPECT_EQ(MathUtils::divide(10, 2), 5); EXPECT_EQ(MathUtils::divide(7, 3), 2); // Integer division}

TEST(MathUtilsTest, DivideByZeroThrows) { EXPECT_THROW(MathUtils::divide(5, 0), std::invalid_argument);}


使用模拟对象



为了隔离模块,通常需要替换依赖项。Google Mock(Google Test 的一部分)允许创建桩件:



// database_interface.hclass DatabaseInterface {public:    virtual ~DatabaseInterface() = default;    virtual bool save(const std::string& data) = 0;};

// user_service.cppclass UserService { DatabaseInterface& db;public: explicit UserService(DatabaseInterface& db) : db(db) {} bool registerUser(const std::string& name) { return db.save("user:" + name); }};

// test_user_service.cpp#include <gmock/gmock.h>

class MockDatabase : public DatabaseInterface {public: MOCK_METHOD(bool, save, (const std::string&), (override));};

TEST(UserServiceTest, RegisterUserCallsDb) { MockDatabase mockDb; EXPECT_CALL(mockDb, save("user:Alice")).WillOnce(testing::Return(true));

UserService service(mockDb); EXPECT_TRUE(service.registerUser("Alice"));}


优点: 执行速度快(毫秒级),错误定位精确,无需外部依赖即可运行。
缺点: 不检查真实组件之间的交互。



2. 集成测试:检查组件连接



集成测试检查多个模

博客

书籍推荐