使用 Gcov 和 LCOV 度量 C/C++ 项目的代码覆盖率
本篇分享如何使用 Gcov 和 LCOV 对 C/C++ 项目进行代码覆盖率的度量,以及在之前 关于代码覆盖率(Code Coverage) 篇中没有提到的观点写在了本文最后的《不要高估代码覆盖率指标》部分。
如果你想了解代码覆盖率工具 Gcov 是如何工作的,或是以后需要做 C/C++ 项目的代码覆盖率,希望本篇对你有所帮助。
问题
不知道你没有遇到过和我一样的问题:几十年前的 C/C++ 项目没有单元测试,只有回归测试,但是想知道回归测试测了哪些代码?还有哪些代码没测到?代码覆盖率是多少?今后哪些地方需要提高自动化测试用例?
可能对于接触过 Java 的 Junit 和 JaCoCo 的人来说,没有单元测试应该测不了代码覆盖率吧 ... 其实不然,如果不行就没有下文了 :)
现状
市场上有一些工具可以针对黑盒测试来衡量代码覆盖率 Squish Coco,Bullseye 等,它们的原理就是在编译的时候插入 Instrumentation,中文叫插桩,在运行测试的时候用来跟踪和记录运行结果。
其中我比较深入的了解过 Squish Coco[1] 它如何使用,但对于大型项目,引入这类工具都或多或少的需要解决编译上的问题。也正是因为有一些编译问题没有解决,就一直没有购买这款价格不菲的工具 License。
当我再次重新调查代码覆盖率的时候,我很惭愧的发现原来正在使用的 GCC 其实有内置的代码覆盖率的工具的,叫 Gcov[2]
前提条件
对于想使用 Gcov 的人,为了说明它是如何工作的,我准备了一段示例程序,运行这个程序之前需要先安装 GCC[3] 和 LCOV[4]。
如果没有环境或不想安装,可以直接查看示例仓库的 GitHub 仓库:https://github.com/shenxianpeng/gcov-example
注:主分支 master
下面放的是源码,分支 coverage
下的 out
目录是最终的结果报告。
# 这是我的测试环境上的 GCC 和 lcov 的版本 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
就可以编译了。
make
make 命令的输出
sh-4.2$ make 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
and -ftest-coverage
。在编译成功后,不仅生成了 main
and .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
文件,每个源文件都对应一个 .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
代码覆盖率文件。 -
有了代码覆盖率
.gcov
文件,通过 LCOV[5] 生成可视化代码覆盖率报告。
生成 HTML 结果报告的步骤如下:
# 1. 生成 coverage.info 数据文件 lcov --capture --directory . --output-file coverage.info # 2. 根据这个数据文件生成报告 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[6],使用 Python 开发的,它的报告在显示方式上与 LCOV 略有不同。比如 LCOV 以目录结构显示, gcovr 以文件路径来显示,前者与代码结构一直因此我更倾向于使用前者。
不要高估代码覆盖率指标
代码覆盖率不是灵丹妙药,它只是告诉我们有哪些代码没有被测试用例“执行到”而已,高百分比的代码覆盖率不等于高质量的有效测试。
首先,高代码覆盖率不足以衡量有效测试。相反,代码覆盖率更准确地给出了代码未被测试程度的度量。这意味着,如果我们的代码覆盖率指标较低,那么我们可以确定代码的重要部分没有经过测试,然而反过来不一定正确。具有高代码覆盖率并不能充分表明我们的代码已经过充分测试。
其次,100%
的代码覆盖率不应该是我们明确努力的目标之一。这是因为在实现 100%
的代码覆盖率与实际测试重要的代码之间总是需要权衡。虽然可以测试所有代码,但考虑到为了满足覆盖率要求而编写更多无意义测试的趋势,当你接近此限制时,测试的价值也很可能会减少。
借 Martin Fowler 在这篇测试覆盖率[7]的文章说的一句话:
代码覆盖率是查找代码库中未测试部分的有用工具,然而它作为一个数字说明你的测试有多好用处不大。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
2021-2022 世界质量报告(World Quality Report)
前言 2021-22 世界质量报告(World Quality Report 简称 WQR)是由 Micro Focus,Capgemini 和 Sogeti 三家公司合作的来分析软件质量和测试趋势在全球范围内唯一的报告。 这份报告共采访了 1750 名高管和专业人士。从最高管理层到 QA 测试经理和质量工程师,涵盖了来自全球 32 个国家的 10 个行业。 世界质量报告(WQR)是一项独一无二的全球研究,今年的调查强调了新部署方法中不断变化的受大流行影响的应用程序需求的影响,以及 QA 对敏捷和 DevOps 实践的采用,AI 的持续增长。 作为测试关注这类软件质量报告可以帮助我们快速了解软件测试行业的现状和趋势。 五大主题 WQR 的一个关键信息:在新冠疫情依旧的今天,我们看到了数字化转型的融合以及敏捷和 DevOps 实践的实时采用。此外,QA 正在成为采用敏捷和 DevOps 实践的领导者,为团队提供工具和流程以促进整个软件生命周期(SDLC)的质量。 WQR 围绕关键发现和趋势突出了五个特定主题: 新冠疫情对 QA 组织和软件测试的影响 数字化转型与 DevOps 和敏捷采用...
- 下一篇
编写 Dockerfile 最佳实践
官方仓库虽然有数十万计的免费镜像,但大多数无法直接满足公司业务需求,这就需要我们自己去定制镜像了。 Docker通过Dockerfile自动构建镜像,Dockerfile是一个包含用于组建镜像的文本文件,由一条一条的指令组成。 这里,给你提供5点编写建议,可帮助你编写高效易用的Dockerfile。 1、减少镜像层 一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。 例如: FROM centos:7 MAINTAINER www.aliangedu.cn RUN yuminstallepel-release-y RUN yuminstall-y gcc gcc-c++ make -y RUN wgethttp://docs.php.net/distributions/php-5.6.36.tar.gz RUN tar zxf php-5.6.36.tar.gz RUN cd php-5.6.36 RUN ./configure--prefix=/usr/local/php RUN make -j4 RUN makeinstall EXPOSE9...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8安装Docker,最新的服务器搭配容器使用