我们的主线内容其实都已经结束了, 这里先补充一些项目建设性方面的内容, 首先就是根据单元测试生成代码覆盖率的测试报告。
代码仓库:Vanilla-Beauty/tiny-lsm: A KV storage engine based on LSM Tree, supporting Redis RESP 感谢您的 Star
!
欢迎支持本项目同步更新的从零开始实现的视频教程:https://avo6166ew2u.feishu.cn/docx/LXmVdezdsoTBRaxC97WcHwGunOc
欢迎加入讨论群:Tiny-LSM项目交流群
1 为什么需要代码覆盖率?
代码覆盖率测试是软件开发过程中验证测试完整性的重要手段,它通过统计程序中被执行的代码比例来评估测试用例的有效性。常见的代码覆盖率类型包括:
- 行覆盖率(Line Coverage):衡量源文件中被测试执行的代码行数。
- 函数覆盖率(Function Coverage):确认每个函数是否都被调用。
- 分支覆盖率(Branch Coverage):检查程序中的条件判断是否都被覆盖。
常见工具
以下是几种主流的代码覆盖率测试工具,按语言和技术栈分类说明:
工具 | 语言/平台 | 简要说明 |
---|---|---|
gcov / lcov | C/C++ (GCC) | gcov 是 GCC 自带的覆盖率分析工具,lcov 是其可视化前端,可生成 HTML 报告。 |
Valgrind + Gcov | C/C++ | 结合使用 Valgrind 的 callgrind 工具进行更精确的覆盖率分析。 |
Coverage.py | Python | 针对 Python 的代码覆盖率工具,支持分支覆盖率,并集成 unittest 和 pytest。 |
JaCoCo | Java | Java 平台的标准覆盖率工具,支持 Ant、Maven、Gradle 构建系统,能与 Jenkins 等 CI 工具集成。 |
Istanbul / nyc | JavaScript | 常用于 Node.js 项目,支持 ES6+,并能生成详细的 HTML 报告。 |
dotCover | .NET | JetBrains 提供的商业工具,用于 .NET 框架和 .NET Core 的单元测试覆盖率分析。 |
OpenCppCoverage | C/C++ (Windows) | 支持 Windows 平台的代码覆盖率工具,适合 MSVC 编译器环境。 |
常见的工作流
自动化测试流程整合:
- 可将覆盖率测试脚本集成到 CI/CD 流水线(如 GitHub Actions、GitLab CI、Jenkins)中,确保每次提交都自动运行并生成报告。
质量门禁设置:
- 利用工具提供的阈值配置功能(例如
lcov
配合genhtml
或coverage.py
),设定最低覆盖率要求,低于该值则构建失败。
- 利用工具提供的阈值配置功能(例如
持续改进:
- 定期查看覆盖率报告,针对未覆盖代码设计补充测试用例,提升整体测试质量和代码可靠性。
2 工具链使用介绍
2.1 工具链说明
本项目由于采用了 xmake
构建系统,因此我们将使用 xmake
、lcov
和 genhtml
等工具来生成代码覆盖率报告。以下是这些工具的简要说明:
工具 | 说明 |
---|---|
xmake | 一款现代构建系统,简洁灵活,支持多平台和构建模式(如覆盖率模式)。 (这个系列用了这么久就不再过多介绍了 ) |
lcov | gcov 的图形化封装,生成 .info 格式的覆盖率数据文件。 |
genhtml | 读取 .info 文件并生成 HTML 格式的可视化代码覆盖率报告。 |
gcov | GCC 的代码覆盖率分析工具,生成 .gcno 、.gcda 数据文件供 lcov 使用。 |
2.2 工具链安装
为了顺利使用 xmake
、lcov
和 genhtml
工具生成代码覆盖率报告,需要在系统中安装这些工具。以下是各工具的安装说明,按不同操作系统分类。
2.2.1 lcov 安装
lcov
是基于 gcov
的前端工具,用于收集和处理覆盖率数据。
1 | sudo apt-get install lcov # Ubuntu/Debian |
验证是否安装成功:
1 | lcov --version |
2.2.2 genhtml 安装
genhtml
是 lcov
的一部分,安装 lcov
后会自动包含 genhtml
,无需单独安装。
验证是否可用:
1 | genhtml --version |
2.2.3 gcov 安装(GCC 工具链)
gcov
是 GCC 自带的覆盖率分析工具,通常随编译器一起安装。
Linux
确保已安装 GCC:
1 | sudo apt-get install gcc g++ |
macOS
默认可能使用的是 Clang,需手动安装 GCC(例如通过 Homebrew):
1 | brew install gcc |
验证是否安装成功:
1 | gcov --version |
提示:
- 若使用的是 CI 环境(如 GitHub Actions),可在
.yml
文件中添加上述安装命令。- 对于 Windows 平台若使用 MSVC 编译器,可考虑使用 OpenCppCoverage 替代方案。
3 获取代码覆盖率报告
3.1 配置文件修改
为了获取代码覆盖率测试, 我们在编译和链接文件时需要附上--coverage
标志, 我们不妨再设置一个编译模式:
1 | -- 在 coverage 模式下设置 flags |
在 coverage
模式下:
- 使用
--coverage
编译器参数,以生成用于覆盖率分析的额外信息。 - 使用
--coverage
链接器参数,以确保链接了必要的覆盖率运行库(如gcov
)。
3.2 测试脚本说明
脚本文件示例:generate_coverage.sh
1 |
|
为了更好地理解 generate_coverage.sh
, 以下是对整个流程中关键步骤的详细解释。
3.3 获取代码覆盖率的基本原理
3.3.1 编译阶段:插入覆盖率信息
在使用 GCC 编译器时,通过添加编译选项(如 -fprofile-arcs
和 -ftest-coverage
或直接使用 --coverage
),编译器会在生成的目标文件中插入额外的探针(instrumentation code):
.gcno
文件:- 在编译阶段生成。
- 包含程序结构信息(如函数、基本块、分支等)。
- 用于将运行时数据映射回源码。
__gcov_init
,__gcov_exit
等调用:- 插入到函数入口和出口。
- 用于记录执行路径。
3.3.2 运行阶段:收集执行路径数据
当程序运行时,这些探针会记录每条语句和分支是否被执行,并在程序正常退出时将结果写入 .gcda
文件:
.gcda
文件:- 每个
.o
文件对应一个.gcda
文件。 - 包含该模块中各行代码/分支的实际执行次数。
- 每个
⚠️ 注意:程序必须正常退出(如调用
exit()
或从 main 返回),否则可能无法正确生成.gcda
文件。
3.3.3 数据采集与过滤
脚本使用 lcov
工具进行数据采集:
1 | lcov --capture --directory . --output-file coverage.info |
- 遍历当前目录及其子目录,收集所有
.gcno
和.gcda
文件。 - 将其转换为统一的
coverage.info
格式,便于后续处理。
随后通过 --remove
命令过滤掉不关心的路径(如系统头文件、构建缓存、测试代码):
1 | lcov --remove coverage.info '/usr/*' '*/.xmake/*' '*/test/*' -o coverage.cleaned.info |
这一步有助于聚焦项目核心代码,避免干扰。
3.3.4 报告生成
最后,使用 genhtml
将 .info
文件转换为 HTML 可视化报告:
1 | genhtml -o coverage-report coverage.cleaned.info |
生成的 HTML 页面中:
- 每个源文件都有对应的覆盖率统计。
- 行号颜色区分已覆盖(绿色)、未覆盖(红色)。
- 支持点击进入具体函数或文件查看细节。
4 gcov相关知识点
为了更清晰地理解代码覆盖率工具链中涉及的命令、参数和文件类型,以下是对 gcov
相关知识点的结构化整理,包括编译参数、生成文件、常用命令及其作用。
4.1 编译参数说明
参数 | 含义 |
---|---|
-fprofile-arcs |
记录程序执行路径(分支信息),用于分析控制流。 |
-ftest-coverage |
生成 .gcno 文件,记录源码结构信息,供后续覆盖率分析使用。 |
--coverage |
GCC 提供的快捷选项,等价于同时启用 -fprofile-arcs 和 -ftest-coverage ,并链接 gcov 运行时库。 |
✅ 推荐在构建测试版本时使用
--coverage
,确保编译器和链接器都正确插入探针。
4.2 生成文件说明
文件类型 | 来源阶段 | 描述 |
---|---|---|
.gcno |
编译阶段 | 包含函数、基本块、分支等源码结构信息,用于将运行时数据映射回源文件。 |
.gcda |
运行阶段 | 程序执行后生成,记录每条语句和分支的实际执行次数。 |
.info |
lcov 输出 |
由 lcov 收集 .gcno 和 .gcda 生成的中间格式文件,便于后续处理。 |
4.3 常用命令说明
4.3.1 lcov 命令
命令 | 功能描述 |
---|---|
lcov --capture --directory . --output-file coverage.info |
收集当前目录下所有模块的 .gcno 和 .gcda 文件,合并为一个 .info 文件。 |
lcov --remove coverage.info '/usr/*' '*/.xmake/*' '*/test/*' -o coverage.cleaned.info |
去除与项目无关的路径(如系统库、缓存、测试代码),提升报告准确性。 |
lcov --list coverage.info |
查看 .info 文件中的覆盖信息内容。 |
lcov --extract coverage.info 'src/*' -o filtered.info |
提取特定路径下的覆盖率数据。 |
4.3.2 genhtml 命令
命令 | 功能描述 |
---|---|
genhtml -o coverage-report coverage.cleaned.info |
将 .info 文件转换为 HTML 格式报告,支持浏览器查看。 |
genhtml --title "My Project Coverage" -o coverage-report coverage.cleaned.info |
自定义报告标题。 |
genhtml --legend -o coverage-report coverage.cleaned.info |
显示详细图例,包括未覆盖行数和百分比。 |
4.4 流程简要回顾
- 编译阶段:使用
--coverage
编译,生成.gcno
。 - 运行阶段:执行测试用例,生成
.gcda
。 - 采集阶段:使用
lcov --capture
收集.gcno
和.gcda
。 - 过滤阶段:使用
lcov --remove
移除不关心的路径。 - 生成阶段:使用
genhtml
生成 HTML 报告,可视化展示。