Kotlin: java.lang.NoSuchMethodError in tests

12k Views Asked by At

Is it possible to use Kotlin package functions and package properties in different sourcesets? When I try to do so, I have NoSuchMethodError thrown.


Example

I have Gradle project with Kotlin code and two sourcesets in it, main and test. In main, I have the following code in one of the files:

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

In test I try to access payloadSplitter with the following code:

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

And exactly in the first line where payloadSplitter is accessed, at runtime I get

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

Other global variables and functions are also inaccessible in test with the same error.


UPD Kotlin team explained the issue and announced the fix here.

3

There are 3 best solutions below

2
On BEST ANSWER

For properties and methods outside of classes, Kotlin creates a java class named ${packagename}Package with the properties and methods implemented as static methods and variables. With multiple source-sets, the java class will be created twice, once for each source-set. Your issue is that the test source-set "package class" is hiding the class compiled in the main source-set.

As mentioned in the comments above, avoid having any top-level properties or methods in the test source-set to prevent the Kotlin compiler from creating this package class in the test output directory.

0
On

I faced similar issue when testing kotlin-native module, it was fixed by adding this dependencies:

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

In addition to what was suggested earlier, I found another workaround: if you need package-level functions or properties in test just move the tests to different package, e.g. in your test sources:

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

and then do

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

which is everything from your main package. This will make Kotlin compliler generate two non-conflicting Package classes, therefore both can have global members.