Kotlin:java.lang.NoSuchMethodError 在测试中

Kotlin: java.lang.NoSuchMethodError in tests

是否可以在不同的源集中使用 Kotlin 包函数和包属性?当我尝试这样做时,我抛出了 NoSuchMethodError


例子

我有 Gradle 个项目,其中包含 Kotlin 代码和两个源集,maintest。 在 main 中,我在其中一个文件中包含以下代码:

package ru.ifmo.ctddev.igushkin.dkvs
...
public val payloadSplitter: String = " ### "

test 中,我尝试使用以下代码访问 payloadSplitter

package ru.ifmo.ctddev.igushkin.dkvs
...
public class MessageTests {
    ...
    test fun testParsing() {
        ...
        checkParseAndToString("p1b 345 ${payloadSplitter} set a b c")
    }
    ...
}

并且恰好在访问 payloadSplitter 的第一行,在运行时我得到

java.lang.NoSuchMethodError: ru.ifmo.ctddev.igushkin.dkvs.DkvsPackage.getPayloadSplitter()Ljava/lang/String;

test中也无法访问其他全局变量和函数,并出现同样的错误。


UPD Kotlin 团队解释了这个问题并宣布了修复 here

对于 classes 之外的属性和方法,Kotlin 创建一个名为 ${packagename} 的 java class 包,其中的属性和方法作为静态方法和变量实现。对于多个源集,java class 将被创建两次,每个源集一次。您的问题是测试源集 "package class" 隐藏了在主源集中编译的 class。

如上面的评论所述,避免在测试源集中包含任何顶级属性或方法,以防止 Kotlin 编译器在测试输出目录中创建此包 class。

除了之前建议的之外,我还找到了另一种解决方法:如果您需要 test 中的包级函数或属性,只需将测试移至不同的包,例如在您的测试源中:

 package ru.ifmo.ctddev.igushkin.dkvs.tests

然后

 import ru.ifmo.ctddev.igushkin.dkvs.*

这是您主包中的所有内容。这将使 Kotlin 编译器生成两个不冲突的包 类,因此两者都可以有全局成员。

我在测试 kotlin-native 模块时遇到了类似的问题,通过添加以下依赖项解决了这个问题:

testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"