SonarQube,JaCoCo :(应该是22个条件中的11个)应该是3个(或4个) [英] SonarQube, JaCoCo: (11 of 22 conditions) when they are supposed to be 3 (or 4)
问题描述
我对SonarQube如何计算测试所涵盖的条件一无所知.
I am lost on how SonarQube calculates conditions covered by tests.
使用的工具版本: * JaCoCo 0.8.1 * SonarQube 7.4
Versions of tools used: * JaCoCo 0.8.1 * SonarQube 7.4
这是我的常规代码
boolean condition1(boolean b1, boolean b2) {
!b1 || !b2
}
boolean condition2(boolean b1, boolean b2) {
b1 || b2
}
boolean condition3(boolean b1, boolean b2) {
!b1 && !b2
}
boolean condition4(boolean b1, boolean b2) {
b1 && b2
}
boolean condition5(boolean b1, boolean b2) {
b1 && !b2
}
boolean condition6(boolean b1, boolean b2, boolean b3) {
b1 && b2 && b3
}
这是测试
void "test condition 1"() {
expect:
service.condition1(c1,c2)
where:
c1 | c2
true | true
true | false
false | true
false | false
}
void "test condition 2"() {
expect:
service.condition2(c1,c2)
where:
c1 | c2
true | true
true | false
false | true
false | false
}
void "test condition 3"() {
expect:
service.condition3(c1,c2)
where:
c1 | c2
true | true
true | false
false | true
false | false
}
void "test condition 4"() {
expect:
service.condition4(c1,c2)
where:
c1 | c2
true | true
true | false
false | true
false | false
}
void "test condition 5"() {
expect:
service.condition5(c1,c2)
where:
c1 | c2
true | true
true | false
false | true
false | false
}
void "test condition 6"() {
expect:
service.condition6(c1, c2, c3)
where:
c1 | c2 | c3
true | true | true
true | true | false
true | false | true
true | false | false
false | true | true
false | true | false
false | true | true
false | true | false
false | false | false
}
代码覆盖率报告说不满足这些条件,以下是我获得的唯一信息
The code coverage report says those conditions are not satisfied and the followings are the only info I get
condition1. (11 of 22 conditions)
condition2. (7 of 14 conditions)
condition3. (11 of 22 conditions)
condition4. (7 of 14 conditions)
condition5. (9 of 18 conditions)
condition6. (11 of 22 conditions)
虽然我从逻辑上相信做到了,但这意味着我无法达到100%的涵盖测试.
That means I am not able to reach 100% of covered tests although I believe logically did.
我知道SonarQube文档 https://docs.sonarqube.org/latest/user-guide/metric -definitions/ 它说的是
I am aware of SonarQube documentation https://docs.sonarqube.org/latest/user-guide/metric-definitions/ where it says
在包含一些布尔表达式的每一行代码中,条件覆盖率仅回答以下问题:每个布尔表达式都被评估为true和false吗?".这是单元测试执行期间遵循的流控制结构中可能条件的密度
On each line of code containing some boolean expressions, the condition coverage simply answers the following question: 'Has each boolean expression been evaluated both to true and false?'. This is the density of possible conditions in flow control structures that have been followed during unit tests execution
任何人都知道这实际上是如何工作的,以及我在这里做错了什么?
Anyone has an idea on how this actually works and what I am doing wrong here?
推荐答案
From similar questions (such as "Why is JaCoCo not covering my String switch statements?" and "How does assert groupType != null contain 4 branches")
JaCoCo执行字节码分析
JaCoCo performs analysis of bytecode
因此类似-看一下字节码.
thus similarly - take a look at bytecode.
对于Example.groovy
class Example {
boolean condition2(boolean b1, boolean b2) {
b1 || b2
}
}
Groovy编译器(groovyc --version
)
Groovy compiler (groovyc --version
)
Groovy compiler version 3.0.0-rc-1
Copyright 2003-2019 The Apache Software Foundation. http://groovy-lang.org/
生成(groovyc Example.groovy
)
以下字节码(javap -v -p Example.class
)
generates (groovyc Example.groovy
)
following bytecode (javap -v -p Example.class
)
public boolean condition2(boolean, boolean);
descriptor: (ZZ)Z
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=4, args_size=3
0: invokestatic #20 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_3
4: invokestatic #38 // Method org/codehaus/groovy/runtime/BytecodeInterface8.isOrigZ:()Z
7: ifeq 25
10: getstatic #40 // Field __$stMC:Z
13: ifne 25
16: invokestatic #43 // Method org/codehaus/groovy/runtime/BytecodeInterface8.disabledStandardMetaClass:()Z
19: ifne 25
22: goto 42
25: iload_1
26: ifne 33
29: iload_2
30: ifeq 37
33: iconst_1
34: goto 38
37: iconst_0
38: ireturn
39: nop
40: nop
41: athrow
42: iload_1
43: ifne 50
46: iload_2
47: ifeq 54
50: iconst_1
51: goto 55
54: iconst_0
55: ireturn
56: nop
57: nop
58: nop
59: nop
60: nop
61: nop
62: nop
63: nop
64: athrow
LineNumberTable:
line 2: 4
line 3: 25
line 4: 39
line 3: 42
line 4: 56
LocalVariableTable:
Start Length Slot Name Signature
0 56 0 this LExample;
0 56 1 b1 Z
0 56 2 b2 Z
包含14个分支(每个条件跳转指令ifeq
和ifne
每个分支2个分支),并且您的测试仅覆盖其中的一半(执行路径,其中偏移量7
的第一个ifeq
跳转到偏移量
which contains 14 branches (2 branches per each conditional jump instruction ifeq
and ifne
), and your tests cover only half of them (execution path where first ifeq
at offset 7
jumps to offset 25
), which is absolutely consistent with what is reported by JaCoCo and hence shown in SonarQube.
以下讨论似乎与此处相关- http: //groovy.329449.n5.nabble.com/Branch-coverage-issues-td5686725.html ,因为使用--indy
选项(groovyc --indy Example.groovy
)对其进行编译会产生以下字节码
And following discussion seems to be relevant here - http://groovy.329449.n5.nabble.com/Branch-coverage-issues-td5686725.html , because compilation of the same using --indy
option (groovyc --indy Example.groovy
) produces following bytecode
public boolean condition2(boolean, boolean);
descriptor: (ZZ)Z
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=3, args_size=3
0: iload_1
1: ifne 8
4: iload_2
5: ifeq 12
8: iconst_1
9: goto 13
12: iconst_0
13: ireturn
14: nop
15: nop
16: nop
17: nop
18: nop
19: nop
20: nop
21: nop
22: athrow
LineNumberTable:
line 3: 0
line 4: 14
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LExample;
0 14 1 b1 Z
0 14 2 b2 Z
仅包含4个分支.
这篇关于SonarQube,JaCoCo :(应该是22个条件中的11个)应该是3个(或4个)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!