运行 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 所做的那样)无法意识到无法到达 tableswitchdefault 分支 - 在不更改的情况下向枚举再添加一个值其他任何东西,重新编译,你会看到这个 setType 方法完全相同的字节码。

您可以使用exhaustive

val <T> T.exhaustive: T
get() = this

然后

when (value) {
    Type.SETUP_LOGIN -> nop()
    Type.CHANGE_PIN -> nop()
    Type.CHANGE_FINGERPRINT -> nop()
}.exhaustive