运行 Jacoco 覆盖时缺少 when 和 enum 的分支
Missing branch with when and enum when running Jacoco coverage
我使用 Jacoco 0.8.6,我有一个包含 3 个值的枚举。
我在下图中显示了这个 when
,我对每个分支进行了测试,但 Jacoco 仍然说我缺少一个分支,而且我的 var
是非空的。怎么了?
JaCoCo 执行字节码分析。对于 Example.kt
object Example {
var type: Type = Type.SETUP_LOGIN
set(value) {
field = value
when (value) {
Type.SETUP_LOGIN -> nop()
Type.CHANGE_PIN -> nop()
Type.CHANGE_FINGERPRINT -> nop()
}
}
fun nop() {
}
enum class Type {
SETUP_LOGIN, CHANGE_PIN, CHANGE_FINGERPRINT
}
}
编译者
kotlinc-1.4.30/bin/kotlinc Example.kt
执行
java -v -p Example.class
显示 setType
方法的以下字节码
public final void setType(Example$Type);
descriptor: (LExample$Type;)V
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: ldc #17 // String value
3: invokestatic #23 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_1
7: putstatic #11 // Field type:LExample$Type;
10: aload_1
11: getstatic #29 // Field Example$WhenMappings.$EnumSwitchMapping[=13=]:[I
14: swap
15: invokevirtual #35 // Method Example$Type.ordinal:()I
18: iaload
19: tableswitch { // 1 to 3
1: 44
2: 51
3: 58
default: 65
}
44: aload_0
45: invokevirtual #39 // Method nop:()V
48: goto 65
51: aload_0
52: invokevirtual #39 // Method nop:()V
55: goto 65
58: aload_0
59: invokevirtual #39 // Method nop:()V
62: goto 65
65: return
LineNumberTable:
line 4: 6
line 5: 10
line 6: 44
line 7: 51
line 8: 58
line 9: 65
line 10: 65
如您所见,tableswitch
有 4 个分支,这正是您在 JaCoCo 报告中看到的。
仅查看此类字节码(就像 JaCoCo 所做的那样)无法意识到无法到达 tableswitch
的 default
分支 - 在不更改的情况下向枚举再添加一个值其他任何东西,重新编译,你会看到这个 setType
方法完全相同的字节码。
您可以使用exhaustive
val <T> T.exhaustive: T
get() = this
然后
when (value) {
Type.SETUP_LOGIN -> nop()
Type.CHANGE_PIN -> nop()
Type.CHANGE_FINGERPRINT -> nop()
}.exhaustive
我使用 Jacoco 0.8.6,我有一个包含 3 个值的枚举。
我在下图中显示了这个 when
,我对每个分支进行了测试,但 Jacoco 仍然说我缺少一个分支,而且我的 var
是非空的。怎么了?
JaCoCo 执行字节码分析。对于 Example.kt
object Example {
var type: Type = Type.SETUP_LOGIN
set(value) {
field = value
when (value) {
Type.SETUP_LOGIN -> nop()
Type.CHANGE_PIN -> nop()
Type.CHANGE_FINGERPRINT -> nop()
}
}
fun nop() {
}
enum class Type {
SETUP_LOGIN, CHANGE_PIN, CHANGE_FINGERPRINT
}
}
编译者
kotlinc-1.4.30/bin/kotlinc Example.kt
执行
java -v -p Example.class
显示 setType
方法的以下字节码
public final void setType(Example$Type);
descriptor: (LExample$Type;)V
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: ldc #17 // String value
3: invokestatic #23 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_1
7: putstatic #11 // Field type:LExample$Type;
10: aload_1
11: getstatic #29 // Field Example$WhenMappings.$EnumSwitchMapping[=13=]:[I
14: swap
15: invokevirtual #35 // Method Example$Type.ordinal:()I
18: iaload
19: tableswitch { // 1 to 3
1: 44
2: 51
3: 58
default: 65
}
44: aload_0
45: invokevirtual #39 // Method nop:()V
48: goto 65
51: aload_0
52: invokevirtual #39 // Method nop:()V
55: goto 65
58: aload_0
59: invokevirtual #39 // Method nop:()V
62: goto 65
65: return
LineNumberTable:
line 4: 6
line 5: 10
line 6: 44
line 7: 51
line 8: 58
line 9: 65
line 10: 65
如您所见,tableswitch
有 4 个分支,这正是您在 JaCoCo 报告中看到的。
仅查看此类字节码(就像 JaCoCo 所做的那样)无法意识到无法到达 tableswitch
的 default
分支 - 在不更改的情况下向枚举再添加一个值其他任何东西,重新编译,你会看到这个 setType
方法完全相同的字节码。
您可以使用exhaustive
val <T> T.exhaustive: T
get() = this
然后
when (value) {
Type.SETUP_LOGIN -> nop()
Type.CHANGE_PIN -> nop()
Type.CHANGE_FINGERPRINT -> nop()
}.exhaustive