9

I wonder whather it's possible to run a lambda function passed as a parameter to a mocked function. And run it whenever the mocked method is called.

I am using Mockk and I imagine the code to be something like this:

class DataManager {
   fun submit(lambda: (Int) => Unit) { ... }
}

...

val mock = mockk<DataManager>()

every { mock.submit(lambda = any()) }.run { lambda(5) }

In my real implementation the datamanager calls a server and runs the lambda as a callback when it recieves a successful response. The lambda happens to be a private method of the class under test.

David Holkup
  • 372
  • 2
  • 9

2 Answers2

11

You need to use a Capture instead of Any.

val dataManager: DataManager = mockk()

every { dataManager.submit(captureLambda()) } answers { lambda<(Int) -> Unit>().invoke(5) }

dataManager.submit { i -> println(i) }

Additionally the the declaration of your function type is invalid.

You have (Int) => Unit when it should be (Int) -> Unit.

user2983377
  • 166
  • 1
  • 4
  • 1
    Thanks for a great answer, helped me a lot. But there is a small bug. It should actually be `every { mock.submit(lambda = capture(slot) ) } `. The `capture` is missing in your answer. It would be great if you coud update it :) – David Holkup Apr 09 '20 at 06:41
  • Glad to help. I was guessing at the syntax last night and decided to double check this afternoon. I found out that mockk has specific matchers and answer scope extensions for this scenario. I've updated accordingly. – user2983377 Apr 09 '20 at 16:29
5

Can be solve in the following ways.

with args from answer:

every { dataManager.submit(any()) } answers {
      firstArg<(Int) -> Unit>().invoke(5)
}

or with captureLambda

every { dataManager.submit(captureLambda()) } answers {
      lambda<(Int) -> Unit>().captured.invoke(5)
}
Igor Román
  • 186
  • 1
  • 5