4

I am trying to write a unit test for a implementation of an abstract class I wrote. The method I'm trying to mock takes a lambda as it's only parameter. I'm trying to capture this lambda, so I can invoke it and get the result.

This is the method I'm trying to mock:

protected fun update(block: suspend S.() -> S?): Unit

I am using an extension function in my tests like this:

suspend inline fun <reified T : Model<S>, S : State> T.blah(
    state: S,
    block: (T) -> Unit
): S? {
    val spy = spyk(this, recordPrivateCalls = true)
    val slot = slot<suspend S.() -> S?>()
    every { spy["update"](capture(slot)) } answers { Unit }

    block(spy)
    return slot.captured.invoke(state)
}

So I am creating a spy, then a slot, then when the update function is called, capture it so that it blocks the actual class from performing the call. Then I invoke the lambda myself and return the value.

However I keep getting this error:

io.mockk.MockKException: can't find function update(kotlin.jvm.functions.Function2$Subclass1@6bfa228c) for dynamic call

at io.mockk.InternalPlatformDsl.dynamicCall(InternalPlatformDsl.kt:122) at io.mockk.MockKMatcherScope$DynamicCall.invoke(API.kt:1969)

I followed the stacktrace and set a breakpoint in the InternalPlatformDsl.kt class, and traced it to this block of code:

for ((idx, param) in it.parameters.withIndex()) {
    val classifier = param.type.classifier
    val matches = when (classifier) {
        is KClass<*> -> classifier.isInstance(params[idx])
        is KTypeParameter -> classifier.upperBounds.anyIsInstance(params[idx])
        else -> false
    }

    if (!matches) {
       return@firstOrNull false
    }
}

It successfully matches the first parameter which is the class under test Model in this case, but it fails matching the second parameter because it is wrapped in the capture function.

Any ideas on how I can intercept this update call?

I'm using the latest version of mockk, and JUnit 4

jordond
  • 367
  • 4
  • 15

0 Answers0