blog/docs/accurate/coverage.md

5.0 KiB
Raw Permalink Blame History

title date categories author tags
覆盖率相关概念 2022-01-28 16:07:07:31
精准测试
Anges黎梦
代码覆盖率
精准测试

覆盖率计数器

Jacoco使用一系列的不同的计数器来做覆盖率的度量计算。所有这些计数器都是从java的class文件中获取信息这些class文件可以可选包含调试的信息在里面。即使在没有源码的情况下这种方法也可以实时有效地对应用程序进行度量和分析。在大部分情况下收集到的信息可以映射到源码可视化到每一行代码的粒度。但这种方法还是有一些限制。这些class文件必须使用调试信息来编译这样才可以计算行的覆盖率和提供出源码的高亮。但不是所有的JAVA语言的结构都可以直接编译成一致的二进制代码。在这种情况下java 编译器会创建所谓的“合成”代码,会导致产生一些不期望得到的覆盖率结果。

指令C0 Coverage

Jacoco最小的计数单元是单个java二进制代码指令。指令覆盖率提供了代码是否被执行的信息。这个度量完全独立源码格式并且总是可用即使class文件里面没有调试信息。

分支C1 Coverage

Jacoco也计算分支的覆盖率包括所有的if和switch语句。这个度量计算一个方法里面的总分支数确定执行和不执行的分支数量。分支覆盖率总是可用的即使class文件里面没有调试信息。注意异常处理是不在分支度量里面统计的。

如果class文件使用调试信息编译的话产生的覆盖率可以映射到源码行并且高亮提示

● 没有覆盖:在这一行中没有分支被执行(红色方块)

● 部分覆盖:这一行的分支中只有一部分被执行(黄色方块)

● 完全覆盖:这一行的所有分支都被执行(绿色方块)

圈复杂度

Jacoco同样可以为每一个非抽象方法计算复杂度最终计算出类、包和组的复杂度。根据由McCabe1996圈复杂度的定义是线性组合中计算在一个方法里面所有可能路径的最小数目。所以复杂度可以作为度量单元测试是否有完全覆盖所有场景的一个依据。复杂度即使是在没有调试信息的情况下也可以计算。

圈复杂度VG的正式定义是基于方法的控制流图的有向图表示

v(G) = E N + 2

E是边界的数量N是节点的数量。Jacoco 基于下面的方程来计算复杂度B是分支的数量D是决策点的数量

v(G) = B D + 1

基于每个分支的被覆盖情况Jacoco也为每个方法计算覆盖和缺失的复杂度。缺失的复杂度同样表示测试案例没有完全覆盖到这个模块。注意Jacoco不将异常处理作为分支try/catch块也同样不增加复杂度。

所有的class文件使用debug信息编译之后就可以计算行的覆盖率信息。一行源代码是否被执行要看这一行中是否至少有一个指令被执行。

由于实际上一行代码一般被编译成多个二进制代码指令这样源码在高亮显示时会显示成3种不同的状态

● 没有覆盖:这一行中没有指令被执行(红色背景)

● 部分覆盖:这一行中只有一部分指令被执行(黄色背景)

● 完全覆盖:这一行中所有指令都被覆盖(绿色背景

方法

每一个非抽象方法至少包含一个指令。一个方法是否执行取决于方法中是否有至少一个指令被执行。在Jacoco中构造器和静态初始化同样会像方法一样统计。其中一些方法可能没有可以直接对应的源码比如默认构造器或常量的初始化命令。

一个方法是否执行取决于类中是否有至少一个方法被执行。注意Jacoco认为构造器和静态初始化都是方法。Java的接口一般包含静态初始化所以接口也同样被认为是可执行的类。

覆盖率

覆盖率统计类型:全量代码覆盖率、差异代码覆盖率、增量代码覆盖率

有效代码行数:

字节码解析后,能被执行的代码行。

全量代码覆盖率:

根据版本查看,此版本内所有有效代码行的执行覆盖率。

差异代码覆盖率:

对比两个版本,有效代码行数中差异代码的执行覆盖率。

增量代码覆盖率:

对比两次收集,覆盖率增加的数值。

行覆盖率计算方式:

覆盖率总计:已覆盖行数/过滤后服务中的代码的行数

类级别:已覆盖行数/类中行数

分支覆盖率计算方式:

覆盖率总计:已覆盖分支数/过滤后服务中的代码涉及的分支数量

类级别:已覆盖分支数/类中总分支数

方法覆盖率计算方式:

覆盖率总计:已覆盖方法数/过滤后服务中的代码涉及的方法数量

类级别:已覆盖方法数/类中总方法数