建设工程招标网站申请一个网站
建设工程招标网站,申请一个网站,网站建设属于什么行业分类,网站维护的作用C TDD 入门#xff1a;从搭建 GTest 框架到第一个示例
你想要入门 C 语言的 TDD 实践#xff0c;核心是先搭建测试框架环境#xff0c;再遵循「红-绿-重构」的循环落地最小功能单元。下面我会以 Google Test#xff08;GTest#xff0c;C 最主流的 TDD 测试框架#xff0…C TDD 入门从搭建 GTest 框架到第一个示例你想要入门 C 语言的 TDD 实践核心是先搭建测试框架环境再遵循「红-绿-重构」的循环落地最小功能单元。下面我会以Google TestGTestC 最主流的 TDD 测试框架为例提供从「环境搭建→第一个 TDD 示例→完整循环落地」的分步指南适配 LinuxCentOS/Ubuntu环境新手也能快速上手。一、前置准备环境Linux 系统CentOS 8/9 或 Ubuntu 18.04已安装gC 编译器、cmake构建工具、git拉取 GTest 源码。验证编译器是否安装g --version cmake --version若未安装执行以下命令补装# CentOS/RHEL dnf install -y gcc gcc-c cmake git # Ubuntu/Debian apt update apt install -y g cmake git二、步骤1搭建 Google TestGTest环境GTest 是 C 最成熟、最常用的单元测试框架支持 TDD 所需的自动化测试、断言判断、测试用例隔离等核心功能我们采用「源码编译安装」确保版本最新适配性更好。1.1 拉取 GTest 源码# 创建工作目录后续所有操作均在该目录下进行 mkdir -p ~/cpp_tdd_demo cd ~/cpp_tdd_demo # 拉取 GTest 源码官方镜像稳定版 git clone https://github.com/google/googletest.git1.2 编译并安装 GTestGTest 采用 CMake 构建执行以下命令编译安装安装到系统全局后续所有项目均可直接引用# 进入 googletest 目录创建构建目录 cd googletest mkdir build cd build # 生成 Makefile指定安装路径为 /usr/local系统全局可访问 cmake .. -DCMAKE_INSTALL_PREFIX/usr/local # 编译-j 后接CPU核心数加快编译速度如 -j4 make -j4 # 安装到系统root 权限需输入密码 sudo make install1.3 验证 GTest 安装是否成功安装完成后系统会在/usr/local/include/生成gtest/头文件目录在/usr/local/lib64/CentOS或/usr/local/lib/Ubuntu生成库文件验证命令# 查看头文件是否存在 ls /usr/local/include/gtest # 查看库文件是否存在 ls /usr/local/lib64 | grep gtest # CentOS # ls /usr/local/lib | grep gtest # Ubuntu若能看到gtest.h头文件和libgtest.a、libgtest_main.a库文件说明安装成功。三、步骤2C TDD 入门示例实现一个简单的加法函数我们以「实现一个整数加法函数int Add(int a, int b)」为例完整遵循 TDD 「红-绿-重构」循环这是最适合新手的入门案例。项目结构说明先创建清晰的项目结构TDD 项目需分离「测试代码」和「业务代码」便于维护# 回到 cpp_tdd_demo 目录创建项目结构 cd ~/cpp_tdd_demo mkdir -p add_demo/{src,test} cd add_demosrc/存放业务代码.h 头文件、.cpp 实现文件test/存放 GTest 测试用例代码后续会在add_demo/下创建CMakeLists.txt用于构建整个项目。循环1红Red- 编写失败的测试用例核心先写测试用例明确功能预期此时无业务代码测试必然失败。2.1 编写测试用例代码进入test/目录创建测试文件test_add.cppvim test/test_add.cpp粘贴以下代码GTest 测试用例的标准写法// 引入 GTest 核心头文件 #include gtest/gtest.h // 引入业务代码头文件此时还未创建先声明函数保证编译不报错 // 后续会创建 src/add.h这里先提前声明 int Add(int a, int b); // 定义测试套件Test Suite命名为 AddFunctionTest对应要测试的模块 TEST(AddFunctionTest, NormalInputTest) { // 断言Assert判断 Add(1, 2) 的返回值是否等于 3 // EXPECT_EQ预期相等若不相等则测试失败不会终止整个测试进程 // GTest 还有 ASSERT_EQ断言失败则终止当前测试用例新手优先用 EXPECT_* EXPECT_EQ(Add(1, 2), 3); EXPECT_EQ(Add(0, 0), 0); EXPECT_EQ(Add(-1, 1), 0); EXPECT_EQ(Add(100, 200), 300); } // 测试套件的第二个测试用例测试边界值TDD 要求覆盖边界条件 TEST(AddFunctionTest, BoundaryInputTest) { EXPECT_EQ(Add(INT_MAX, 0), INT_MAX); // 最大整数 0 EXPECT_EQ(Add(INT_MIN, 0), INT_MIN); // 最小整数 0 } // GTest 主函数用于运行所有测试用例可直接复用无需修改 // 也可以不写该主函数编译时链接 libgtest_main.a 即可 int main(int argc, char **argv) { // 初始化 GTest testing::InitGoogleTest(argc, argv); // 运行所有测试用例 return RUN_ALL_TESTS(); }保存退出Esc→:wq。2.2 编写 CMake 构建文件回到add_demo/目录创建CMakeLists.txt用于构建测试项目vim CMakeLists.txt粘贴以下内容# 要求 CMake 最低版本 cmake_minimum_required(VERSION 3.10) # 项目名称cpp_tdd_add_demo project(cpp_tdd_add_demo) # 设置 C 标准C11 及以上均可 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 包含头文件目录src/ 目录后续存放业务头文件 include_directories(${PROJECT_SOURCE_DIR}/src) # 查找 GTest 库系统全局安装可直接找到 find_package(GTest REQUIRED) include_directories(${GTEST_INCLUDE_DIRS}) # 构建测试可执行文件test_add对应 test/test_add.cpp add_executable(test_add test/test_add.cpp) # 链接 GTest 库和 pthread 库GTest 依赖线程库 target_link_libraries(test_add ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)保存退出。2.3 编译并运行测试预期失败执行以下命令构建并运行测试验证「红阶段」# 创建构建目录 mkdir build cd build # 生成 Makefile cmake .. # 编译 make -j4此时编译会报错提示undefined reference to Add(int, int)因为我们只声明了Add函数没有实现业务代码这是「红阶段」的正常现象测试用例无法运行更无法通过。循环2绿Green- 编写最简化业务代码让测试通过核心仅编写刚好能让测试用例通过的业务代码不做多余设计。2.4 编写业务代码头文件进入src/目录创建add.h头文件vim src/add.h粘贴以下内容声明加法函数#ifndef ADD_H // 防止头文件重复包含C 工程规范 #define ADD_H #include climits // 引入 INT_MAX/INT_MIN 定义 // 加法函数声明 int Add(int a, int b); #endif // ADD_H2.5 编写业务代码实现文件在src/目录下创建add.cpp实现Add函数vim src/add.cpp粘贴以下最简化实现代码仅满足测试用例要求不考虑优化// 引入头文件 #include add.h // 加法函数实现最简化逻辑直接返回 a b int Add(int a, int b) { return a b; }2.6 更新 CMakeLists.txt包含业务代码修改add_demo/CMakeLists.txt将src/add.cpp加入编译vim ../CMakeLists.txt # 若在 build 目录下需回到上一级找到add_executable(test_add test/test_add.cpp)修改为# 包含业务代码 add.cpp一起编译 add_executable(test_add test/test_add.cpp src/add.cpp)2.7 重新编译并运行测试预期成功# 若在 build 目录下直接执行 make -j4 # 运行测试可执行文件 ./test_add此时会输出 GTest 测试结果若看到[ PASSED ] 2 tests.说明测试用例全部通过「绿阶段」完成典型成功输出[] Running 2 tests from 1 test suite. [----------] Global test environment set-up. [----------] 2 tests from AddFunctionTest [ RUN ] AddFunctionTest.NormalInputTest [ OK ] AddFunctionTest.NormalInputTest (0 ms) [ RUN ] AddFunctionTest.BoundaryInputTest [ OK ] AddFunctionTest.BoundaryInputTest (0 ms) [----------] 2 tests from AddFunctionTest (0 ms total) [] 2 tests passed.循环3重构Refactor- 优化代码且保持测试通过核心修改代码结构不改变功能测试用例始终保持通过。当前的Add函数逻辑简单可优化的点不多我们以「增加异常处理避免整数溢出 规范代码注释 优化代码可读性」为例进行重构。2.8 重构业务代码add.cpp修改src/add.cpp增加整数溢出判断优化代码#include add.h #include stdexcept // 引入异常处理头文件 /** * brief 整数加法函数支持正常整数相加避免溢出 * param a 第一个整数 * param b 第二个整数 * return 两数之和 * throw std::overflow_error 若相加结果溢出则抛出异常 */ int Add(int a, int b) { // 重构增加整数溢出判断避免 undefined behavior // 情况1正数 正数 溢出 if (a 0 b 0 a INT_MAX - b) { throw std::overflow_error(Positive integer overflow); } // 情况2负数 负数 溢出 if (a 0 b 0 a INT_MIN - b) { throw std::overflow_error(Negative integer overflow); } // 原有功能逻辑不变保证测试用例通过 return a b; }2.9 重构测试用例补充异常测试修改test/test_add.cpp增加溢出异常的测试用例TDD 重构阶段可补充完善测试用例覆盖新的场景// 新增测试用例测试溢出异常 TEST(AddFunctionTest, OverflowTest) { // EXPECT_THROW预期函数抛出指定类型的异常否则测试失败 EXPECT_THROW(Add(INT_MAX, 1), std::overflow_error); EXPECT_THROW(Add(INT_MIN, -1), std::overflow_error); }2.10 重新编译并运行测试确保重构后测试通过# 编译build 目录下 make -j4 # 运行测试 ./test_add此时应看到[ PASSED ] 3 tests.说明重构后的代码功能正常且新增了异常处理代码质量更高「重构阶段」完成。四、TDD 核心补充C 专属1. GTest 常用断言新手必备TDD 中核心是通过断言判断功能是否符合预期GTest 提供了两类断言优先使用EXPECT_*断言类型功能示例EXPECT_EQ(a, b)预期 a b相等EXPECT_EQ(Add(1,2),3)EXPECT_NE(a, b)预期 a ! b不相等EXPECT_NE(Add(1,2),4)EXPECT_GT(a, b)预期 a b大于EXPECT_GT(Add(2,3),4)EXPECT_LT(a, b)预期 a b小于EXPECT_LT(Add(1,2),4)EXPECT_THROW(func, ex)预期 func 抛出 ex 异常EXPECT_THROW(Add(INT_MAX,1), std::overflow_error)2. C TDD 项目的最佳实践分离业务代码与测试代码始终保持src/业务和test/测试目录分离避免测试代码污染业务代码测试用例独立无依赖每个测试用例不依赖其他用例的执行结果不依赖外部环境如文件、数据库可通过「模拟对象Mock」隔离外部依赖GTest 可结合 GMock 实现小步迭代每次只实现一个最小功能单元如先实现正常输入的加法再实现边界值最后实现异常处理重构优先保证测试通过重构过程中可多次执行./test_add确保所有测试用例始终通过避免引入新 Bug自动化构建结合 CI/CD 工具如 Jenkins每次提交代码自动编译并运行测试用例实现持续验证。3. 常见误区先写业务代码再补测试违背 TDD 「测试先行」原则失去 TDD 驱动设计的意义测试用例覆盖不全只测试正常场景忽略边界值、异常场景导致代码鲁棒性不足重构阶段修改功能重构只优化代码结构不改变功能若需新增功能应重新进入「红-绿-重构」循环。五、总结环境搭建核心编译安装 GTest 并配置 CMake实现测试代码与业务代码的编译链接TDD 核心循环红编写失败测试用例→ 绿编写最简业务代码让测试通过→ 重构优化代码且保持测试通过无限重复直至功能完成C 专属要点使用 GTest 断言判断结果分离业务/测试目录重构时增加异常处理等工程化优化入门关键从简单功能如加法、减法入手熟悉 GTest 用法和 TDD 循环再逐步推进到复杂功能。这个示例完成后你可以尝试扩展功能如实现减法、乘法函数按照相同的 TDD 循环落地逐步掌握 C TDD 的核心思维。