JaCoCo 覆盖率报告(针对 Kolin)中检测到的 `encode()` 函数是什么?
What is `encode()` function detected in JaCoCo coverage report (for Kolin)?
最近我将 gradle 从 6.5.1 升级到 7.0,即
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
升级后,我发现我的测试覆盖率下降了。
经过调查,我发现在 Gradle 6.5.1 中,我的 JaCoCo 测试覆盖率报告显示我的一些 class 有一个 encode()
函数,但它不再存在在 Gradle 7.0.
下面我挖出了最简单的例子。代码如下
在 Gradle 6.5 中,我的 JaCoCo 报告如下(注意还有一个额外的 encode()
函数。
然而,在 Gradle 7.0 中,我的 JaCoCo 报告如下
由于缺少覆盖功能,因此我的覆盖范围下降了。尽管如此,在 Gradle 7.0 中看起来更正确,因为我的真实代码没有 encode()
.
我只是想了解 encode()
函数最初在哪里,为什么它不再出现在 Gradle 7.0 中?我假设 Gradle 7.0 结果正确吗?
您似乎在使用 kotlinx.Serialization。
这会为您的对象生成一些 encodeToString 和类似函数。我想 Gradle 7 现在会忽略那些?
不同版本的 Gradle 具有不同的 jacoco.toolVersion
值,您也可以 can change in your build.gradle
控制要使用的 JaCoCo 版本。
Gradle 6.5
by default uses JaCoCo 0.8.5
, and starting from Gradle 6.7
default is 0.8.6
.
这里是 JaCoCo 版本的变更列表 0.8.6
- https://www.jacoco.org/jacoco/trunk/doc/changes.html
很可能您的接口 ContextData
包含具有默认实现的方法 encode
。
JVM 从版本 8 开始支持接口中的默认方法,但是 Kotlin 支持编译为版本 6 的字节码。为此,Kotlin 编译器对此类方法做了一个技巧 - 它在实现此接口的 类 中生成方法仅将执行委托给默认实现:
以下Example.kt
interface ContextData {
fun encode() = { /* something */ }
}
data class SearchRefinementModalOpenData(
val userAction: String?
) : ContextData
执行
kotlin-compiler-1.4.32/bin/kotlinc Example.kt
javap -v -p SearchRefinementModalOpenData.class
显示以下字节码
public final class SearchRefinementModalOpenData implements ContextData
{
public kotlin.jvm.functions.Function0<kotlin.Unit> encode();
descriptor: ()Lkotlin/jvm/functions/Function0;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokestatic #29 // Method ContextData$DefaultImpls.encode:(LContextData;)Lkotlin/jvm/functions/Function0;
4: areturn
JaCoCo starting from version 0.8.6
filters out such methods 因为它们是编译器工件,没有出现在原始源代码中。
最近我将 gradle 从 6.5.1 升级到 7.0,即
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
升级后,我发现我的测试覆盖率下降了。
经过调查,我发现在 Gradle 6.5.1 中,我的 JaCoCo 测试覆盖率报告显示我的一些 class 有一个 encode()
函数,但它不再存在在 Gradle 7.0.
下面我挖出了最简单的例子。代码如下
在 Gradle 6.5 中,我的 JaCoCo 报告如下(注意还有一个额外的 encode()
函数。
然而,在 Gradle 7.0 中,我的 JaCoCo 报告如下
由于缺少覆盖功能,因此我的覆盖范围下降了。尽管如此,在 Gradle 7.0 中看起来更正确,因为我的真实代码没有 encode()
.
我只是想了解 encode()
函数最初在哪里,为什么它不再出现在 Gradle 7.0 中?我假设 Gradle 7.0 结果正确吗?
您似乎在使用 kotlinx.Serialization。
这会为您的对象生成一些 encodeToString 和类似函数。我想 Gradle 7 现在会忽略那些?
不同版本的 Gradle 具有不同的 jacoco.toolVersion
值,您也可以 can change in your build.gradle
控制要使用的 JaCoCo 版本。
Gradle 6.5
by default uses JaCoCo 0.8.5
, and starting from Gradle 6.7
default is 0.8.6
.
这里是 JaCoCo 版本的变更列表 0.8.6
- https://www.jacoco.org/jacoco/trunk/doc/changes.html
很可能您的接口 ContextData
包含具有默认实现的方法 encode
。
JVM 从版本 8 开始支持接口中的默认方法,但是 Kotlin 支持编译为版本 6 的字节码。为此,Kotlin 编译器对此类方法做了一个技巧 - 它在实现此接口的 类 中生成方法仅将执行委托给默认实现:
以下Example.kt
interface ContextData {
fun encode() = { /* something */ }
}
data class SearchRefinementModalOpenData(
val userAction: String?
) : ContextData
执行
kotlin-compiler-1.4.32/bin/kotlinc Example.kt
javap -v -p SearchRefinementModalOpenData.class
显示以下字节码
public final class SearchRefinementModalOpenData implements ContextData
{
public kotlin.jvm.functions.Function0<kotlin.Unit> encode();
descriptor: ()Lkotlin/jvm/functions/Function0;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokestatic #29 // Method ContextData$DefaultImpls.encode:(LContextData;)Lkotlin/jvm/functions/Function0;
4: areturn
JaCoCo starting from version 0.8.6
filters out such methods 因为它们是编译器工件,没有出现在原始源代码中。