原文链接:http://blog.yeyuzhen.cn/?p=203
脑补链接:什么是CMake? 什么是代码覆盖率测试? 什么是 Gcov?
最近不怎么顺利的面试经历,让我觉得自己其实是一个2B程序员。应该是懒的原因,涉及到某技术的实现原理啥的,就觉得很烦人。能用就好,何必执着?所以,一个技术问题下来,都是“晚节不保”。自己更关心的是诸如“如何细粒度化任务,以提高开发效率?”、“如何实践代码覆盖率测试,提高程序的鲁棒性?”这类问题。唉~貌似逼格(项目经理)和现实(程序员)存在不小的差距。
日常开发中,我就很注重测试的环节——功能测试、性能测试。我常和组员说,“代码写的不好可以慢慢学,但是测试一定要用心,程序是一点点测出来的”,“能测出来的问题,不算Bug”。但是经过长期的“感性”测试,不免问自己,“测这些用例就OK了?”、“这块代码有没有问题?”、“测试要如何度量?”。后来了解到“代码覆盖率测试”这么个好东西,可以初步解决测试度量的问题。
完整演示项目Github地址:CMakeGcovSupport
初始项目目录结构:
CMakeGcovSupport
├── CMakeLists.txt
├── bin
├── build
├── include
│ └── name.h
├── libgreeting
│ ├── CMakeLists.txt
│ ├── include
│ │ └── greeting.h
│ └── src
│ ├── CMakeLists.txt
│ ├── greeting.cpp
│ └── yelp.cpp
└── src
├── CMakeGcovSupport.cpp
├── CMakeLists.txt
└── name.cpp
示例程序是个很简单的输出一行问候语的程序。为了演示复杂目录结构下CMake集成Gcov的方法,故意将输出问候语的函数单独放到了 libgreeting 静态库中。执行如下编译命令:
$ cd CMakeGcovSupport $ mkdir build $ cd build $ cmake -DENABLE_COVERAGE=ON .. $ gmake all
执行 CMake 外部编译之后,CMake 在 build 目录内为我们生成了 .gcno 文件:
CMakeGcovSupport
├── CMakeLists.txt
├── bin
│ └── CMakeGcovSupport
├── build
│ ├── ......
│ ├── libgreeting
│ │ ├── ......
│ │ └── src
│ │ ├── CMakeFiles
│ │ │ ├── ......
│ │ │ ├── greeting.dir
│ │ │ │ ├── ......
│ │ │ │ ├── greeting.cpp.gcno
│ │ │ │ ├── greeting.cpp.o
│ │ │ │ ├── ......
│ │ │ │ ├── yelp.cpp.gcno
│ │ │ │ └── yelp.cpp.o
│ │ │ └── ......
│ │ └── ......
│ └── src
│ ├── CMakeFiles
│ │ ├── ......
│ │ ├── CMakeGcovSupport.dir
│ │ │ ├── CMakeGcovSupport.cpp.gcno
│ │ │ ├── CMakeGcovSupport.cpp.o
│ │ │ ├── ......
│ │ │ ├── name.cpp.gcno
│ │ │ ├── name.cpp.o
│ │ │ └── ......
│ │ └── progress.marks
│ └── ......
├── include
├── libgreeting
└── src
为了避免接下来执行程序过程中,未覆盖的源码文件的覆盖率信息丢失,我们需要对覆盖率信息进行初始化操作:
$ cd CMakeGcovSupport $ lcov -d build -z $ lcov -d build -b . --no-external --initial -c -o CMakeGcovSupportInitialCoverage.info
然后我们执行 bin 中的 CMakeGcovSupport, main() 函数中将会调用 Greeting() 和 Name() 函数,而不会调用到 Yelp() 函数。
$ cd CMakeGcovSupport $ cd bin $ ./CMakeGcovSupport $ Hello, gcov.
这时,我们去 .gcno 所在目录,会看到有同名的 .gcda 覆盖率数据文件生成了。执行以下命令,生成覆盖率测试报告:
$ cd CMakeGcovSupport $ lcov -d build -b . --no-external -c -o CMakeGcovSupportCoverage.info $ genhtml -o CMakeGcovSupportCoverageReport --prefix=`pwd` CMakeGcovSupportInitialCoverage.info CMakeGcovSupportCoverage.info
用浏览器打开 CMakeGcovSupportCoverageReport 目录中的 index.html 查看覆盖率报告(Mac + Lcov1.10):
Linux + Lcov1.11覆盖率结果(不会误包含外部头文件覆盖率信息):
以上就是CMake项目初步集成 Gcov/Lcov 的方式。但是,还未深度集成到 CMake 编译过程中,而且覆盖率报告还存在一些瑕疵。下一步计划解决应用“--no-external”选项之后依旧会包含外部头文件覆盖率信息的问题,以及不显示头文件覆盖率信息的问题。最终深度集成 CMake 的效果希望是自定义如下命令:
$ gmake InitialCoverage # 初始化覆盖率信息命令 $ gmake ReportCoverage # 生成覆盖率测试报告命令
参考
[1] 测试覆盖(率)到底有什么用?
[2] Linux 下 C/C++ 项目代码覆盖率的产生方法
[5] 使用gcov,lcov,genhtml进行代码覆盖率测试
[6] 关于C++ code coverage tool 的研究(1)
[7] 关于C++ code coverage tool 的研究(2)—GCOV 实现原理
[8] 关于C++ code coverage tool 的研究(3)—gcov使用实例
编辑历史:
V1.1,增加 Linux + Lcov1.11 下覆盖率报告截图,@2014-11-09
V1.0,初稿,@2014-11-08