本篇简要介绍:什么是代码覆盖率?为什么要做代码覆盖率?代码覆盖率的指标、工作原理,主流的代码覆盖率工具以及不要高估代码覆盖率指标。
什么是代码覆盖率?
代码覆盖率是对整个测试过程中被执行的代码的衡量,它能测量源代码中的哪些语句在测试中被执行,哪些语句尚未被执行。
为什么要测量代码覆盖率?
众所周知,测试可以提高软件版本的质量和可预测性。但是,你知道你的单元测试甚至是你的功能测试实际测试代码的效果如何吗?是否还需要更多的测试?
这些是代码覆盖率可以试图回答的问题。总之,出于以下原因我们需要测量代码覆盖率:
- 了解我们的测试用例对源代码的测试效果
- 了解我们是否进行了足够的测试
- 在软件的整个生命周期内保持测试质量
注:代码覆盖率不是灵丹妙药,覆盖率测量不能替代良好的代码审查和优秀的编程实践。
通常,我们应该采用合理的覆盖目标,力求在代码覆盖率在所有模块中实现均匀覆盖,而不是只看最终数字的是否高到令人满意。
举例:假设代码覆盖率只在某一些模块代码覆盖率很高,但在一些关键模块并没有足够的测试用例覆盖,那样虽然代码覆盖率很高,但并不能说明产品质量就很高。
代码覆盖率的指标种类
代码覆盖率工具通常使用一个或多个标准来确定你的代码在被自动化测试后是否得到了执行,常见的覆盖率报告中看到的指标包括:
- 函数覆盖率:定义的函数中有多少被调用
- 语句覆盖率:程序中的语句有多少被执行
- 分支覆盖率:有多少控制结构的分支(例如if语句)被执行
- 条件覆盖率:有多少布尔子表达式被测试为真值和假值
- 行覆盖率:有多少行的源代码被测试过
代码覆盖率是如何工作的?
代码覆盖率测量主要有以下三种方式:
1. Source code instrumentation - 源代码检测
将检测语句添加到源代码中,并使用正常的编译工具链编译代码以生成检测的程序集。这是我们常说的插桩,Gcov 是属于这一类的代码覆盖率工具。
2. Runtime instrumentation - 运行时收集
这种方法在代码执行时从运行时环境收集信息以确定覆盖率信息。以我的理解 JaCoCo 和 Coverage 这两个工具的原理属于这一类别。
3. Intermediate code instrumentation - 中间代码检测
通过添加新的字节码来检测编译后的类文件,并生成一个新的检测类。说实话,我 Google 了很多文章并找到确定的说明哪个工具是属于这一类的。
了解这些工具的基本原理,结合现有的测试用例,有助于正确的选择代码覆盖率工具。比如:
- 产品的源代码只有 E2E(端到端)测试用例,通常只能选择第一类工具,即通过插桩编译出的可执行文件,然后进行测试和结果收集。
- 产品的源代码有单元测试用例,通常选择第二类工具,即运行时收集。这类工具的执行效率高,易于做持续集成。
当前主流代码覆盖率工具
代码覆盖率的工具有很多,以下是我用过的不同编程语言的代码覆盖率工具。在选择工具时,力求去选择那些开源、流行(活跃)、好用的工具。
编程语言 | 代码覆盖率工具 |
---|---|
C/C++ | Gcov |
Java | JaCoCo |
JavaScript | Istanbul |
Python | Coverage.py |
Golang | cover |
不要高估代码覆盖率指标
代码覆盖率不是灵丹妙药,它只是告诉我们有哪些代码没有被测试用例“执行到”而已,高百分比的代码覆盖率不等于高质量的有效测试。
首先,高代码覆盖率不足以衡量有效测试。相反,代码覆盖率更准确地给出了代码未被测试程度的度量。这意味着,如果我们的代码覆盖率指标较低,那么我们可以确定代码的重要部分没有经过测试,然而反过来不一定正确。具有高代码覆盖率并不能充分表明我们的代码已经过充分测试。
其次,100%
的代码覆盖率不应该是我们明确努力的目标之一。这是因为在实现 100%
的代码覆盖率与实际测试重要的代码之间总是需要权衡。虽然可以测试所有代码,但考虑到为了满足覆盖率要求而编写更多无意义测试的趋势,当你接近此限制时,测试的价值也很可能会减少。
借 Martin Fowler 在这篇测试覆盖率的文章说的一句话:
代码覆盖率是查找代码库中未测试部分的有用工具,然而它作为一个数字说明你的测试有多好用处不大。
参考
https://www.lambdatest.com/blog/code-coverage-vs-test-coverage/
https://www.atlassian.com/continuous-delivery/software-testing/code-coverage
https://www.thoughtworks.com/insights/blog/are-test-coverage-metrics-overrated