Search code examples
unit-testingkotlinmockk

Mockk: Mock a global function with overloads


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?


Solution

  • 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.