Home > Software engineering >  Mock generic top level suspend function with mockk
Mock generic top level suspend function with mockk

Time:10-27

I have a function inside a class that is using a generic top level suspend function. In order to test this function I would need to mock this top level function, but so far I have not found a nice solution.

Lets say I have this:

suspend fun <T> awesoneGenericFunction(block: suspend (Bool) -> T): T {
    complicatedCode()
    return otherAwesomeCode(block)
}

With mockk it is possible to mock a static function by doing:

mockkStatic(::awesoneGenericFunction)

Sadly in this case this does not work because awesoneGenericFunction is generic and the compiler is complaining that the type is missing. I know I can also do this:

mockkStatic("pckg.FileWithGenericFunctionKt")
coEvery { awesoneGenericFunction <Boolean>(any()) } returns false

This is working, but this approach does not feel right. Hard wiring the file(name) which contains the generic function seems like it could cause trouble in the future (eg if someone decide to move the function to some other file this test will fail. Also in this case the error message is somehow misleading which I believe will lead to some headache).

Is it possible to mock just the function without any further "wiring"?

CodePudding user response:

Here's a workaround that works for me.

val function: suspend (suspend (Boolean) -> Any) -> Any = ::awesomeGenericFunction
val kFunction = function as KFunction<*>
mockkStatic(kFunction)

It uses two tricks:

  • We can make a reference to the function by defining an explicit function type for it, in this case suspend (suspend (Boolean) -> Any) -> Any. This means the compiler doesn't have to infer a value for the generic type because it's provided as part of the function type.
  • We can then cast the function to a KFunction<*>, because it actually is one under the hood. This is a bit of an implementation detail, so there's a slight possibility it could stop working in future versions of the language.

Because this trick involves creating an explicit signature for the function, I can't think of a way to make a universal helper that would mock any generic function. The code would need to be different for each function according to its function signature.

There's an open YouTrack issue to allow proper function references for functions with generic type parameters, which would remove the need for a workaround.

  • Related