Аналогично « Почему 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
)
А вот соответствующие скриншоты отчета JaCoCo для выполнения того же исходного файла
Переход к пакетуНа уровне вы можете видеть 100% покрытие линии, но 50% покрытие ветви
И затем переходя к уровню класса по первой ссылке ExampleKt.main.new Function2() {...}
Вы снова можете видеть, что метод invokeSuspend(Object)
добавляет пропущенные ветви
Обновление (29/01/2019)
JaCoCo версии 0.8.3 имеет фильтр для веток, добавленный компилятором Kotlin для приостановки лямбд и функций: