kotlinmockk

How to mock a function that accepts a callback in kotlin


Let's say I have the following two classes:

class Foo {
    fun <RES> execute(callback: () -> RES): RES {
        return callback.invoke()
    }
}

class Bar(
    private val foo: Foo,
) {
    fun perform(): String {
        return foo.execute {
            "Hello World"
        }
    }
}

When testing Bar I would like to mock the call to Foo#execute

I tried the following using MockK (expecting the test to print "Mock Answer"):

class BarTest {
    private val foo: Foo = mockk()
    private val bar = Bar(foo)

    @Test
    fun test() {
        every {
            foo.execute {
                "Hello World"
            }
        }.answers {
            "Mock Answer"
        }
        println(bar.perform())
    }
}

However, I get the below exception:

io.mockk.MockKException: no answer found for Foo(#1).execute(lambda {}) among the configured answers: (Foo(#1).execute(eq(lambda {}))))

I imagine that this is happening because the callback is being created as an anonymous class and thus the two objects are different albeit both returning the string "Hello World", my question is there a way to actually accomplish this using MockK or otherwise?

Also, If I try to create one callback object such as val callback = { "Hello World" } and then pass it to Foo#execute in both Bar#perform and the test, I get the expected result, however this is of course not going to work in a real scenario.


Solution

  • You can use Capturing slot to mock the lambda response

       @Test
       fun test() {
         val slot = slot<() -> Any>()
         every {
           foo.execute (capture(slot))
         }.answers {
           "Mock Answer"// slot.captured.invoke()
         }
         assertEquals("Mock Answer", bar.perform())
       }