Неверное покрытие кода Jacoco для сопрограммы Kotlin - PullRequest
0 голосов
/ 26 ноября 2018

Я использую Jacoco для покрытия кода модульного теста.Сгенерированный отчет Jacoco показывает, что пропущено несколько ветвей в моем коде Котлина .Я замечаю код сопрограммы и код после этого не покрывается должным образом в соответствии с Jacoco.Я не уверен, что это из-за сопрограммы или чего-то еще.Во время выполнения моего модульного теста с IntelliJ Code Coverage мой класс Kotlin показывает 100% охват .

Я не знаю, почему Джакоко показывает меньше освещения.Я написал свои модульные тесты, используя Спока (Groovy).

Пожалуйста, обратитесь к изображениям ниже:

Пропущенные ветви: enter image description here

enter image description here

Оригинальный код: enter image description here

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Jacoco версия 0.8.3 исправляет это, он был выпущен вчера, 24 января.

Полный журнал изменений можно найти здесь: https://github.com/jacoco/jacoco/releases

0 голосов
/ 01 декабря 2018

Аналогично « Почему JaCoCo не покрывает мои операторы переключателя String? »:

JaCoCo выполняет анализ байт-кода, а не исходного кода .Компиляция Example.kt с kotlinc 1.3.10

package example

fun main(args: Array<String>) {
    kotlinx.coroutines.runBlocking { // line 4
    }
}

приводит к двум файлам ExampleKt.class и ExampleKt$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

, который связан со строкой 4 исходного файла и содержит ветви (ifeq, tableswitch).

В то время как последняя на сегодня версия JaCoCo (0.8.2) имеет фильтры для различных сгенерированных компиляторомАртефакты, такие как String в операторе switch, байт-код, который компилятор Kotlin генерирует для сопрограмм, не фильтруется.Журнал изменений можно увидеть на https://www.jacoco.org/jacoco/trunk/doc/changes.html И среди других на https://www.jacoco.org/research/index.html есть также презентация о сопоставлении с шаблоном байт-кода , которая показывает / объясняет многие сгенерированные компилятором артефакты.


То, что вы видите в IntelliJ IDEA как 100%, - это только покрытие линии, поэтому вы пытаетесь сравнить две совершенно разные вещи.В качестве доказательства - вот скриншот IntelliJ IDEA, который показывает 100% покрытие линии, но была выполнена только одна ветвь if (где args.size >= 0 оценивается как true)

intellij

А вот соответствующие скриншоты отчета JaCoCo для выполнения того же исходного файла

jacoco source level

Переход к пакетуНа уровне вы можете видеть 100% покрытие линии, но 50% покрытие ветви

jacoco package level

И затем переходя к уровню класса по первой ссылке ExampleKt.main.new Function2() {...}Вы снова можете видеть, что метод invokeSuspend(Object) добавляет пропущенные ветви

jacoco class level


Обновление (29/01/2019)

JaCoCo версии 0.8.3 имеет фильтр для веток, добавленный компилятором Kotlin для приостановки лямбд и функций:

before

after

...