代码覆盖(Code Coverage)是软件测试中的一种度量,描述源代码被测试的比例和程度,所得比例称为代码覆盖率。在做单元测试时,代码覆盖率常常被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况,比如,代码覆盖率必须达到80%或90%。于是乎,测试人员费尽心思设计案例覆盖代码。用代码覆盖率来衡量,有利也有弊。
度量方式
函数覆盖
函数覆盖(Function Coverage),执行到程序中的每一个函数(或副程式)。
语句覆盖
语句覆盖(Statement Coverage),又称行覆盖(Line Coverage),段覆盖(Segment Coverage),基本块覆盖(Basic Block Coverage),这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,因此就不会包括像C++的头文件声明,代码注释,空行,等等。非常好理解,只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{}也常常被统计进去。语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。假如你的上司只要求你达到语句覆盖,那么你可以省下很多功夫,但是,换来的确实测试效果的不明显,很难更多地发现代码中的问题。
判断覆盖
判断覆盖(Decision Coverage),又称分支覆盖(Branch Coverage),所有边界覆盖(All-Edges Coverage),基本路径覆盖(Basic Path Coverage),判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到。这句话是需要进一步理解的,应该非常容易和下面说到的条件覆盖混淆。
条件覆盖
条件覆盖(Condition Coverage),它度量判定中的每个子表达式结果true和false是否被测试到。
路径覆盖
路径覆盖(Path Coverage),又称断言覆盖(Predicate Coverage)。它度量了是否函数的每一个分支都被执行了。 这句话也非常好理解,就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合,可想而知,测试路径随着分支的数量指数级别增加。
代码覆盖测试工具
Codecov
Codecov网站是一个开源的测试结果展示平台,将测试结果可视化。Github上许多开源项目都使用了Codecov来展示单测结果。Codecov只是代码覆盖测试报告托管平台,一般是与Travis CI、GitHub Action等工具集成。Travis CI或GitHub Action等可以建立覆盖测试环境,在其中安装如Python的coverage等包执行覆盖测试,然后生成代码覆盖测试报告,上传到Codecov。所以实际做覆盖测试的是coverage等具体工具包,而非网站。
Python程序的覆盖测试
这里以coverage举例,也可使用pytest-cov。貌似只能做语句覆盖测试。
1 | # 安装覆盖测试的Python包 |
使用Travis CI构建环境、测试以及上传到Codecov
1 | dist: xenial |
codecov包作用:Find coverage reports for all the languages below, gather them and submit them to Codecov.
可见只是一个测试报告上传工具,GitHub上的源代码只有一个文件。
总结
通过上面的学习,我们再回头想想,覆盖率数据到底有多大意义。总结如下几个观点:
- 覆盖率数据只能代表你测试过哪些代码,不能代表你是否测试好这些代码。
- 不要过于相信覆盖率数据。
- 不要只拿语句覆盖率(行覆盖率)来考核你的测试人员。
- 覆盖强弱:路径覆盖 > 判定覆盖 > 语句覆盖
- 测试人员不能盲目追求代码覆盖率,而应该想办法设计更多更好的案例,哪怕多设计出来的案例对覆盖率一点影响也没有。