'How to call a lambda callback with mockk

I create a mock of a class with mockk. On this mock I now call a method that gets a lambda as a parameter.

This lambda serves as a callback to deliver state changes of the callback to the caller of the method.

class ObjectToMock() {
    fun methodToCall(someValue: String?, observer: (State) -> Unit) {
        ...
    }
}

How do I configure the mock to call the passed lambda?



Solution 1:[1]

You can use answers:

val otm: ObjectToMock = mockk()
every {  otm.methodToCall(any(), any())} answers {
    secondArg<(String) -> Unit>().invoke("anything")
}

otm.methodToCall("bla"){
    println("invoked with $it") //invoked with anything
}

Within the answers scope you can access firstArg, secondArg etc and get it in the expected type by providing it as a generic argument. Note that I explicitly used invoke here to make it more readable, it may also be omitted.

Solution 2:[2]

I had to look for a bit more example for the callback and found some example in Kotlin Test with Mockk. In my case, it's a bit more specific. I wanted to check and mock the onFailure and onSuccess case of a a custom callback implementation MyCustomCallback implementing the ListenableFutureCallback.

The code would look like that for my ExampleProducer class that would have a send function:

fun send(data: String) {
    val responseFuture = kafkaTemplate.send(topic, data)
    responseFuture.addCallback(MyCustomCallback())
}

So here who would the test go:

@Test
fun onFailureTest() {
    kafkaTemplate: KafkaTemplate<String, String> = mockk()
    val captureCallback = slot<ListenableFutureCallback<SendResult<String, String>>>()
    
    every { callback.addCallback(capture(captureCallback)) } answers {
               captureCallback.captured.onFailure(Throwable())
    }
    every { kafkaTemplate.send(any()) } returns callback
    
    val prod: ExampleProducer = ExampleProducer()
    prod.send("test")
    
    // Then you can verify behaviour or check your captureCallback.captured
    verify { kafkaTemplate.send(any()) }
    assertNotNull(captureCallback.captured)
}

Solution 3:[3]

Maybe not exactly what you ask about, but you can use the funciton type for the mock:

val observerMock = mockk<(State) -> Unit>()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Marius K