Kotlin协程的Jacoco代码覆盖率不正确

Sah*_*bra 5 code-coverage spock jacoco kotlin kotlinx.coroutines

我正在使用Jacoco进行单元测试代码覆盖。Jacoco生成的报告显示,我的Kotlin代码几乎没有遗漏任何分支。我注意到协程代码,之后的代码根据Jacoco未被正确覆盖。我不确定这是因为协程或其他原因。使用IntelliJ代码覆盖率运行单元测试时,我的Kotlin类显示100%的覆盖率

我不知道为什么Jacoco的报道范围减少了。我已经使用Spock(Groovy)编写了单元测试。

请参考以下图片:

错过的分支: 在此处输入图片说明

在此处输入图片说明

原始代码: 在此处输入图片说明

God*_*din 5

类似于“ JaCoCo为什么不覆盖我的String开关语句? ”:

JaCoCo将执行字节码而非源代码的分析。编译Example.ktkotlinc 1.3.10

package example

fun main(args: Array<String>) {
    kotlinx.coroutines.runBlocking { // line 4
    }
}
Run Code Online (Sandbox Code Playgroud)

导致两个文件ExampleKt.classExampleKt$main$1.class,最后一个(字节码javap -v -p ExampleKt$main$1.class)包含方法invokeSuspend(Object)

  public final java.lang.Object invokeSuspend(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_FINAL
    Code:
      stack=3, locals=4, args_size=2
         0: invokestatic  #29                 // Method kotlin/coroutines/intrinsics/IntrinsicsKt.getCOROUTINE_SUSPENDED:()Ljava/lang/Object;
         3: astore_3
         4: aload_0
         5: getfield      #33                 // Field label:I
         8: tableswitch   { // 0 to 0
                       0: 28
                 default: 53
            }
        28: aload_1
        29: dup
        30: instanceof    #35                 // class kotlin/Result$Failure
        33: ifeq          43
        36: checkcast     #35                 // class kotlin/Result$Failure
        39: getfield      #39                 // Field kotlin/Result$Failure.exception:Ljava/lang/Throwable;
        42: athrow
        43: pop
        44: aload_0
        45: getfield      #41                 // Field p$:Lkotlinx/coroutines/CoroutineScope;
        48: astore_2
        49: getstatic     #47                 // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
        52: areturn
        53: new           #49                 // class java/lang/IllegalStateException
        56: dup
        57: ldc           #51                 // String call to 'resume' before 'invoke' with coroutine
        59: invokespecial #55                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
        62: athrow
      LineNumberTable:
        line 4: 3
        line 5: 49
Run Code Online (Sandbox Code Playgroud)

其与源文件的第4行相关联,并且包含分支(ifeqtableswitch)。

JaCoCo版本(0.8.2)的最新版本具有针对各种编译器生成的构件(例如Stringin switch语句)的过滤器,而Kotlin编译器为协程生成的字节码未过滤。可以在https://www.jacoco.org/jacoco/trunk/doc/changes.html上查看Changelog 。此外,在https://www.jacoco.org/research/index.html上也可以找到有关字节码模式的演示匹配显示/解释了许多编译器生成的工件。


您在IntelliJ IDEA中看到的是100%-仅仅是线路覆盖率,因此您正在尝试比较两个完全不同的事物。作为证明-这是IntelliJ IDEA的屏幕截图,该屏幕截图显示了100%的行覆盖率,但是只if执行了一个分支(其中的args.size >= 0计算结果为true

智慧

这是JaCoCo报告的相应屏幕截图,用于执行相同的源文件

jacoco源代码级别

升级到包装级别,您可以看到100%的线路覆盖率,但看到50%的分支覆盖率

jacoco封装级别

然后通过第一个链接下降到类级别,ExampleKt.main.new Function2() {...}您可以再次看到该方法invokeSuspend(Object)有助于遗漏分支

雅各科级别


更新(29/01/2019)

JaCoCo版本0.8.3具有用于Kotlin编译器添加的分支的过滤器,用于挂起lambda和函数:

之前

后