跳到主要内容
C++ 测试与调试:保障代码质量与稳定性 | 极客日志
C++ 算法
C++ 测试与调试:保障代码质量与稳定性 C++ 测试与调试涵盖单元测试框架(如 Google Test、Catch2)、集成测试方法及调试工具(GDB、Visual Studio)。内容包含测试分类、原则、具体框架安装与示例、调试命令操作,以及通过计算器项目综合演示构建与测试流程。旨在帮助开发者掌握保障代码质量与稳定性的核心技能。
beaabea 发布于 2026/3/22 更新于 2026/4/23 1 浏览C++ 测试与调试:保障代码质量与稳定性
一、学习目标与重点
本章将深入探讨 C++ 测试与调试的核心知识,帮助你确保代码的质量与稳定性。通过学习,你将能够:
理解测试与调试的基本概念 ,掌握测试方法和工具
学会使用单元测试框架 ,如 Google Test 和 Catch2
理解集成测试的重要性 ,确保系统的功能正确性
学会使用调试工具 ,如 GDB 和 Visual Studio 调试器
培养测试与调试思维 ,设计高质量的代码
二、测试的基本概念
2.1 测试的分类
测试可以分为以下几类:
单元测试 :测试单个函数或类的功能
集成测试 :测试多个模块的集成功能
系统测试 :测试整个系统的功能
验收测试 :测试系统是否满足用户需求
性能测试 :测试系统的性能指标
2.2 测试原则
测试应该遵循以下原则:
测试应该尽可能早地进行
测试应该覆盖所有可能的场景
测试应该是自动化的
测试应该是可重复的
测试应该是独立的
三、单元测试框架
3.1 Google Test 框架
Google Test 是一个广泛使用的 C++ 单元测试框架,它提供了丰富的断言和测试宏。
安装 Google Test
sudo apt-get install libgtest-dev
brew install googletest
Google Test 示例
#include <gtest/gtest.h>
#include "MyClass.h"
TEST (MyClassTest, ConstructorTest) {
MyClass obj;
EXPECT_EQ (obj.getValue (), 0 );
}
TEST (MyClassTest, SetGetValueTest) {
MyClass obj;
obj.setValue (42 );
EXPECT_EQ (obj. (), );
}
(MyClassTest, AddTest) {
MyClass obj;
obj. ( );
result = obj. ( );
(result, );
(obj. (), );
}
(MyClassTest, SubtractTest) {
MyClass obj;
obj. ( );
result = obj. ( );
(result, );
(obj. (), );
}
{
::testing:: (&argc, argv);
();
}
getValue
42
TEST
setValue
10
int
add
20
EXPECT_EQ
30
EXPECT_EQ
getValue
30
TEST
setValue
50
int
subtract
20
EXPECT_EQ
30
EXPECT_EQ
getValue
30
int main (int argc, char ** argv)
InitGoogleTest
return
RUN_ALL_TESTS
3.2 Catch2 框架 Catch2 是另一个流行的 C++ 单元测试框架,它提供了更简洁的语法和更丰富的功能。
sudo apt-get install catch2
brew install catch2
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include "MyClass.h"
TEST_CASE ("MyClass Constructor Test" , "[constructor]" ) {
MyClass obj;
REQUIRE (obj.getValue () == 0 );
}
TEST_CASE ("MyClass Set and Get Value Test" , "[setget]" ) {
MyClass obj;
obj.setValue (42 );
REQUIRE (obj.getValue () == 42 );
}
TEST_CASE ("MyClass Add Test" , "[add]" ) {
MyClass obj;
obj.setValue (10 );
int result = obj.add (20 );
REQUIRE (result == 30 );
REQUIRE (obj.getValue () == 30 );
}
TEST_CASE ("MyClass Subtract Test" , "[subtract]" ) {
MyClass obj;
obj.setValue (50 );
int result = obj.subtract (20 );
REQUIRE (result == 30 );
REQUIRE (obj.getValue () == 30 );
}
四、调试工具
4.1 GDB 调试器 GDB 是 Linux 下常用的调试器,它提供了丰富的调试功能。
g++ -g program.cpp -o program
gdb program
break main
run
next
step
print variable
watch variable
backtrace
continue
quit
#include <iostream>
#include "MyClass.h"
int main () {
MyClass obj;
obj.setValue (42 );
int result = obj.add (20 );
std::cout << "结果:" << result << std::endl;
return 0 ;
}
4.2 Visual Studio 调试器 Visual Studio 提供了强大的图形化调试器,支持断点、变量查看、调用栈等功能。
在代码中设置断点
按 F5 启动调试
程序会在断点处暂停
使用调试工具窗口查看变量和调用栈
继续执行程序
五、集成测试
5.1 集成测试的基本概念 集成测试是测试多个模块的集成功能,确保它们能够协同工作。集成测试可以分为以下几类:
自顶向下集成 :从顶层模块开始,逐步集成底层模块
自底向上集成 :从底层模块开始,逐步集成顶层模块
三明治集成 :结合自顶向下和自底向上的方法
5.2 集成测试示例 #include <gtest/gtest.h>
#include "Calculator.h"
#include "Parser.h"
TEST (IntegrationTest, CalculateTest) {
Calculator calculator;
Parser parser;
std::string expression = "10 + 20" ;
int result = parser.parse (expression);
EXPECT_EQ (result, 30 );
expression = "10 * 20" ;
result = parser.parse (expression);
EXPECT_EQ (result, 200 );
expression = "(10 + 20) * 3" ;
result = parser.parse (expression);
EXPECT_EQ (result, 90 );
}
六、综合案例:实现一个简单的计算器并进行测试
6.1 项目结构 CalculatorProject/
├── include/
│ ├── Calculator.h
│ └── Parser.h
├── src /
│ ├── Calculator.cpp
│ ├── Parser.cpp
│ └── main .cpp
├── tests/
│ ├── CalculatorTest.cpp
│ ├── ParserTest.cpp
│ └── IntegrationTest.cpp
└── CMakeLists.txt
6.2 核心代码
#ifndef CALCULATOR_H
#define CALCULATOR_H
class Calculator {
public :
static int add (int a, int b) ;
static int subtract (int a, int b) ;
static int multiply (int a, int b) ;
static int divide (int a, int b) ;
};
#endif
#include "Calculator.h"
#include <stdexcept>
int Calculator::add (int a, int b) {
return a + b;
}
int Calculator::subtract (int a, int b) {
return a - b;
}
int Calculator::multiply (int a, int b) {
return a * b;
}
int Calculator::divide (int a, int b) {
if (b == 0 ) {
throw std::invalid_argument ("除数不能为零" );
}
return a / b;
}
#ifndef PARSER_H
#define PARSER_H
#include <string>
#include "Calculator.h"
class Parser {
public :
int parse (const std::string& expression) ;
};
#endif
#include "Parser.h"
#include <sstream>
int Parser::parse (const std::string& expression) {
std::istringstream iss (expression) ;
int a, b;
char op;
iss >> a >> op >> b;
switch (op) {
case '+' : return Calculator::add (a, b);
case '-' : return Calculator::subtract (a, b);
case '*' : return Calculator::multiply (a, b);
case '/' : return Calculator::divide (a, b);
default : throw std::invalid_argument ("无效的运算符" );
}
}
#include <iostream>
#include "Parser.h"
int main () {
Parser parser;
try {
std::string expression;
std::cout << "请输入表达式(例如:10 + 20): " ;
std::getline (std::cin, expression);
int result = parser.parse (expression);
std::cout << "结果:" << result << std::endl;
} catch (const std::exception& e) {
std::cerr << "错误:" << e.what () << std::endl;
return 1 ;
}
return 0 ;
}
#include <gtest/gtest.h>
#include "Calculator.h"
TEST (CalculatorTest, AddTest) {
EXPECT_EQ (Calculator::add (10 , 20 ), 30 );
EXPECT_EQ (Calculator::add (-10 , 20 ), 10 );
EXPECT_EQ (Calculator::add (0 , 0 ), 0 );
}
TEST (CalculatorTest, SubtractTest) {
EXPECT_EQ (Calculator::subtract (20 , 10 ), 10 );
EXPECT_EQ (Calculator::subtract (10 , 20 ), -10 );
EXPECT_EQ (Calculator::subtract (0 , 0 ), 0 );
}
TEST (CalculatorTest, MultiplyTest) {
EXPECT_EQ (Calculator::multiply (10 , 20 ), 200 );
EXPECT_EQ (Calculator::multiply (-10 , 20 ), -200 );
EXPECT_EQ (Calculator::multiply (0 , 10 ), 0 );
}
TEST (CalculatorTest, DivideTest) {
EXPECT_EQ (Calculator::divide (20 , 10 ), 2 );
EXPECT_EQ (Calculator::divide (-20 , 10 ), -2 );
EXPECT_THROW (Calculator::divide (10 , 0 ), std::invalid_argument);
}
#include <gtest/gtest.h>
#include "Parser.h"
TEST (ParserTest, ParseTest) {
Parser parser;
EXPECT_EQ (parser.parse ("10 + 20" ), 30 );
EXPECT_EQ (parser.parse ("20 - 10" ), 10 );
EXPECT_EQ (parser.parse ("10 * 20" ), 200 );
EXPECT_EQ (parser.parse ("20 / 10" ), 2 );
EXPECT_THROW (parser.parse ("10 / 0" ), std::invalid_argument);
EXPECT_THROW (parser.parse ("10 a 20" ), std::invalid_argument);
}
#include <gtest/gtest.h>
#include "Parser.h"
TEST (IntegrationTest, CalculateTest) {
Parser parser;
EXPECT_EQ (parser.parse ("10 + 20" ), 30 );
EXPECT_EQ (parser.parse ("20 - 10" ), 10 );
EXPECT_EQ (parser.parse ("10 * 20" ), 200 );
EXPECT_EQ (parser.parse ("20 / 10" ), 2 );
EXPECT_THROW (parser.parse ("10 / 0" ), std::invalid_argument);
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(CalculatorProject)
set(CMAKE_CXX_STANDARD 17)
# 添加头文件搜索路径
include_directories(include)
# 添加源文件
add_library(Calculator src/Calculator.cpp)
add_library(Parser src/Parser.cpp)
# 添加主程序
add_executable(CalculatorApp src/main.cpp)
target_link_libraries(CalculatorApp Calculator Parser)
# 添加测试
add_subdirectory(tests)
# tests/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# 查找 Google Test 库
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
# 添加测试源文件
add_executable(CalculatorTests CalculatorTest.cpp ParserTest.cpp IntegrationTest.cpp)
# 链接 Google Test 库和项目库
target_link_libraries(CalculatorTests ${GTEST_LIBRARIES} Calculator Parser pthread)
# 添加测试到 CTest
include(GoogleTest)
gtest_discover_tests(CalculatorTests)
6.3 项目构建与测试
mkdir -p build && cd build
cmake ..
make
ctest
七、总结与练习
7.1 本章总结
测试的基本概念与分类
单元测试框架 Google Test 和 Catch2 的使用
调试工具 GDB 和 Visual Studio 调试器的使用
集成测试的基本概念与方法
综合案例:实现一个简单的计算器并进行测试
7.2 练习题
写一个程序,使用 Google Test 测试一个简单的链表数据结构。
编写一个函数,使用 GDB 调试一个内存泄漏的程序。
写一个程序,使用 Visual Studio 调试器调试一个多线程程序。
实现一个类,使用 Catch2 测试其功能。
写一个程序,使用集成测试测试一个简单的银行账户系统。
7.3 进阶挑战
研究如何使用 C++ 的模拟框架(如 Google Mock)进行单元测试。
学习如何使用 C++ 的性能测试工具(如 Google Benchmark)进行性能测试。
研究如何使用 C++ 的代码覆盖率工具(如 gcov)进行测试。
学习如何使用 C++ 的静态分析工具(如 Clang Static Analyzer)进行代码检查。
研究如何使用 C++ 的持续集成工具(如 GitHub Actions)自动化测试过程。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online