Mockk: Mock a global function with overloads
Asked Answered
P

2

5

Mockk added support for mocking global functions.

However, when they have overloads there's a problem.

For example if you try to mock delay() with mockkStatic(::delay) you encounter this error:

Overload resolution ambiguity: 
public suspend fun delay(timeMillis: Long): Unit defined in kotlinx.coroutines
public suspend fun delay(duration: Duration): Unit defined in kotlinx.coroutines

Is there a way to mock a global function that has overloads?

Preceding answered 16/8, 2022 at 9:44 Comment(0)
A
4

That one is a bit tricky, because it seems to be impossible to access the declaring class of such a global function using Kotlin reflection. However, it is possible to use Java reflection, if you know at least one other function in the same file that is not overloaded.

Let's for instance assume that you mean delay of coroutines, there is the function awaitCancellation defined in the same file.

We can use that to access the Java class that declares delay and query it for the right implementation of delay:

val declaringClass = ::awaitCancellation.javaMethod!!.declaringClass
val methods = declaringClass.declaredMethods
val ref = methods.mapNotNull { it.kotlinFunction }
    .filter { it.name == "delay" }
    .first { it.parameters[0].type == Long::class.createType() }
mockkStatic(ref)

In this example, ref points to the implementation of delay that takes a Long as parameter.

For the other implementation we would need to replace Long with Duration in the last condition.

Anthropophagi answered 17/8, 2022 at 21:57 Comment(1)
It's a pity there's not an easier way. But nicely done, thanks!Preceding
Z
2

You can just call mockStatic on another function from the same file, it will mock the whole file. So for example mockkStatic(::awaitCancellation).
Doc:

In jvm environments you can replace the class name with a function reference: mockkStatic(Obj::extensionFunc)
Note that this will mock the whole pkg.FileKt class, and not just extensionFunc.

You can also use the full classname string, for example mockkStatic("kotlin.io.FilesKt__UtilsKt")

Zinck answered 2/4 at 8:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.