Hello guys, I have a problem when mocking a Kotlin...
# announcements
j
Hello guys, I have a problem when mocking a Kotlin class in Java with Mockito. The kotlin class has a
reified
method and my Mockito is presumably choosing the wrong method for some reason. So when running my tests, Mockito either chooses the method I want to mock or chooses the
reified
Kotlin method, which then turns into an Exception because the return types do not match. Did someone run into this problem already or know how to fix this?
The method I want to mock is in line 247, the
reified
method that gets chosen by Mockito is in line 254: https://github.com/tipsy/javalin/blob/be8910b3e867e1662663fbedb4e914c4262aff64/javalin/src/main/java/io/javalin/http/Context.kt#L246-L254
I have written some more detailed information in this ticket if that helps: https://github.com/tipsy/javalin/issues/979
s
Inline functions are not mockable. They’re syntactic sugar.
j
@Sam Garfinkel I do not want to mock them. Mockito chooses to mock that inline function over the function I really want to mock
s
Oh I see the problem. Honestly I’m surprised the compiler is allowing this. The inline function collides with the other header function and is therefore ambiguous.
j
@Sam Garfinkel so I assume what you are saying is that the code of the
Context.kt
class should be modified?
s
I don’t know enough about mockito to be sure tbh. I assume there’s a way to select a particular method to mock by return type.
But yes the functions in Context.kt should be refactored to eliminate ambiguity.
j
I'm pinging @tipsy here, he's the author of Javalin and helps me to figure out this bug. Maybe he can explain the usage or necessity of that "ambiguos" method
t
👋 it's not really ambiguous from kotlin, and from java it's invisible, so i'm not sure what the correct way to work around whatever mockito does is. it doesn't have to be named the same as non-reified version i suppose, but it doesn't make sense to choose naming based on mockito magic either.
the functions in Context.kt should be refactored to eliminate ambiguity.
header("myheader")
and
header<Int>("myheader"))
are good method names imo 🤔
s
I think the problem here is that the compiler is inlining the function call
header("myHeader", Any::class)
for whatever reason when you call
when(context.header("myHeader"))
I don’t have mockito handy but the problem would be clear by looking at the generated bytecode.
@tipsy What is the defined type of
foo
in the following
val foo = context.header("myHeader")
? Does the compiler say type inference fails or does it assume
String?
. If the latter, that seems like a somewhat crazy feature of the compiler.
t
It's
String?
Since you didn't provide a type, it chooses the other method. Doesn't seem crazy to me.
s
That seems like a bug to me, and very inconsistent. It seems like it should be an ambiguous type inference since both
inline fun <reified T> header(value: String): Validator<T>
and
fun header(value: String): String?
are both satisfied by the expression above.