Kotlin: java.lang.NoSuchMethodError in tests
Asked Answered
S

3

18

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.

Sacculate answered 25/5, 2015 at 21:3 Comment(6)
Do you have any top level functions/properties in ru.ifmo.ctddev.igushkin.dkvs package in tests?Sari
How do you run the tests? Could you post your gradle config? It looks like the test package is compiled against the main package but is ran without it.Senzer
@SalomonBRYS, github.com/h0tk3y/dkvs/blob/master/build.gradle -- here it is.Sacculate
@NataliaUkhorskaya, yes. I have a top level property. I'll try to remove it a little bit later.Sacculate
@Sacculate How do you run the tests ? Via an editor or via command line ? If the latter, which command ?Senzer
@NataliaUkhorskaya, thanks, I removed the package-level property from test and it started working. I suggest you posting an answer with this solution. I would also be happy to know what is the exact reason of such a strange behaviour.Sacculate
C
19

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.

Cassey answered 29/5, 2015 at 7:40 Comment(2)
Thanks. There's one more workaround which follows from what you said, I posted it as another answer.Sacculate
Another side note to this solution; at least in Gradle, you need to run a clean build, or the test runner will still find the generated Package class.Resplendence
S
5

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.

Sacculate answered 1/6, 2015 at 20:30 Comment(0)
E
0

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"
Exequies answered 27/11, 2018 at 23:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.