使用 Gcov 和 LCOV 对 C/C++ 项目进行代码覆盖测试
本文分享如何使用 Gcov 和 LCOV 来衡量 C/C++ 项目的代码覆盖率。如果你想了解 Gcov 是如何工作的,或者你需要在以后衡量 C/C++ 项目的代码覆盖率,希望这篇文章对你有用。
问题
我遇到的问题:几十年前的AC/C++项目没有单元测试,只有回归测试,但是你想知道回归测试测试的是什么代码吗?哪些代码未经测试?什么是代码覆盖率?未来自动化测试用例需要在哪些方面进行改进?
没有单元测试可以测量代码覆盖率吗?是的。
C/C++ 的代码覆盖工具
市面上有一些工具可以衡量黑盒测试的代码覆盖率,比如Squish Coco、Bullseye等,它们的原理是在构建产品时插入instrumentation。
我对 Squish Coco 做了一些研究,因为一些未解决的编译问题,我没有为这个昂贵的工具购买许可证。当我再次调查代码覆盖时,我发现 GCC 有一个内置的代码覆盖工具,叫做 Gcov。
先决条件
对于那些想使用 Gcov 的人,为了说明它是如何工作的,我准备了一个示例程序,需要在运行程序之前安装 GCC 和 LCOV。
如果你没有环境或者不想安装它,你可以查看这个示例 存储库
注:源代码在 master
分支 master 下,代码覆盖结果 html 在分支下 coverage
。
# This is the version of GCC and lcov on my test environment.
sh-4.2$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
sh-4.2$ lcov -v
lcov: LCOV version 1.14
Gcov 的工作原理
Gcov工作流程图
主要分为三个步骤:
- 向 GCC 编译添加特殊编译选项以生成可执行文件,以及
*.gcno
. - 运行(测试)生成的可执行文件,生成
*.gcda
数据文件。 - 使用
*.gcno
和*.gcda
,gcov
从源代码生成文件,最后生成代码覆盖率报告。
以下是每个步骤的准确完成方式。
1.编译
第一步是编译。编译用到的参数和文件都已经写在 makefile
.
make build
点击查看 make 命令的输出
sh-4.2$ make build
gcc -fPIC -fprofile-arcs -ftest-coverage -c -Wall -Werror main.c
gcc -fPIC -fprofile-arcs -ftest-coverage -c -Wall -Werror foo.c
gcc -fPIC - fprofile-arcs -ftest-coverage -o main main.o foo.o
从输出中可以看出,该程序是使用两个编译选项编译的 -fprofile-arcs
, -ftest-coverage
. 编译成功后,不仅生成了 main
和 .o
文件,还生成了两个 .gcno
文件。
.gcno
记录文件是在添加 GCC 编译选项后生成的, -ftest-coverage
其中包含在编译过程中重建基本块映射和为块分配源代码行号的信息。
2.运行可执行文件
编译后 main
生成可执行文件,运行(测试)如下
./main
点击查看运行 main 时的输出
sh-4.2$ ./main
Start calling foo() ...
when num is equal to 1...
when num is equal to 2...
运行时 main
,结果记录在 .gcda
数据文件中,如果查看当前目录,可以看到 .gcda
生成了两个文件。
$ ls
foo.c foo.gcda foo.gcno foo.h foo.o img main main.c main.gcda main.gcno main.o makefile README.md
.gcda
记录数据文件的产生是因为程序是用 -fprofile-arcs
引入的选项编译的。它包含弧过渡计数、值分布计数和一些摘要信息。
3.生成报告
make report
点击查看生成报告的输出
sh-4.2$ make report gcov main.c foo.c File 'main.c' Lines executed:100.00% of 5 Creating 'main.c.gcov' File 'foo.c' Lines executed:85.71% of 7 Creating 'foo.c.gcov' Lines executed:91.67% of 12 lcov --capture --directory . --output-file coverage.info Capturing coverage data from . Found gcov version: 4.8.5 Scanning . for .gcda files ... Found 2 data files in . Processing foo.gcda geninfo: WARNING: cannot find an entry for main.c.gcov in .gcno file, skipping file! Processing main.gcda Finished .info-file creation genhtml coverage.info --output-directory out Reading data file coverage.info Found 2 entries. Found common filename prefix "/workspace/coco" Writing .css and .png files. Generating output. Processing file gcov-example/main.c Processing file gcov-example/foo.c Writing directory view page. Overall coverage rate: lines......: 91.7% (11 of 12 lines) functions..: 100.0% (2 of 2 functions)
执行 make report
生成 HTML 报告实际上执行了此命令后面的两个主要步骤。
- 结合编译运行时生成的
.gcno
和.gcda
文件,执行gcov main.c foo.c
生成.gcov
代码覆盖率文件的命令。 - 使用代码覆盖率文件,通过LCOV
.gcov
生成可视化代码覆盖率报告 。
生成 HTML 结果报告的步骤如下。
# 1. Generate the coverage.info data file
lcov --capture --directory . --output-file coverage.info
# 2. Generate a report from this data file
genhtml coverage.info --output-directory out
删除所有生成的文件
可以通过执行 make clean
命令删除所有生成的文件。
点击查看 make clean 命令的输出
sh-4.2$ make clean
rm -rf main *.o *.so *.gcno *.gcda *.gcov coverage.info out
代码覆盖率报告
主页以目录结构显示
进入目录后,显示该目录下的源文件
蓝色表示这些语句被覆盖
红色表示未被覆盖的语句
LCOV 支持语句、函数和分支覆盖率指标。
旁注:还有另一个用于生成 HTML 报告的工具,称为 gcovr,它是用 Python 开发的,其报告的显示方式与 LCOV 略有不同。比如lcov以目录结构显示,gcovr 以文件路径显示,和代码结构总是一样的,所以我更喜欢用前者。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论