Mockito ArgumentCaptor for Kotlin function

Based on mfulton26's answer, i create an example below.

to show how to invoke the captured function or lambda expression.

you need the mockito-kotlin


Assume we have a Class A, it has a suspend function with two higher order function as parameters.

how can we mock the onSuccess scenario and onError scenario

class A {
    suspend fun methodB(onSuccess: (ModelA) -> Unit, onError: (ErrorA) -> Unit)
}

Here is the dummy example

// in the unit test class

private val mockClassA = // use annotation or mock()

// decalre the higer oder function capture variables.
private val onSuccessCapture = argumentCaptor<(ModelA) -> Unit>()
private val onErrorCapture = argumentCaptor<(ErrorA) -> Unit>()


@Test
fun testMethodB = testDispatcher.runBlockingTest {

   doAnswer {
       // on success scenario 
       val modelA = // get ModelA
       onSuccessCapture.firstValue.invoke(modelA) // this line will let the onSuccess parameter been called

       // on error scenario
       // val errorA = // get ErrorA
       //onErrorCapture.firstValue.invoke(errorA)

   }.`when`(mockClassA).methodB(onSuccessCapture.capture(), onErrorCapture.capture())
   
}

I had this problem just now and solved it with an inline argumentCaptor from mockito-kotlin:

argumentCaptor<String>().apply {
  verify(myClass, times(2)).setItems(capture())

  assertEquals(2, allValues.size)
  assertEquals("test", firstValue)
}

firstValue is a reference to the first captured object.

Source: https://github.com/mockito/mockito-kotlin/wiki/Mocking-and-verifying#argument-captors


I recommend nhaarman/mockito-kotlin: Using Mockito with Kotlin

It solves this through an inline function with a reified type parameter:

inline fun <reified T : Any> argumentCaptor() = ArgumentCaptor.forClass(T::class.java)

Source: mockito-kotlin/ArgumentCaptor.kt at a6f860461233ba92c7730dd42b0faf9ba2ce9281 · nhaarman/mockito-kotlin

e.g.:

val captor = argumentCaptor<() -> Unit>()
verify(someClass).doSomeThing(captor.capture())

or

val captor: () -> Unit = argumentCaptor()
verify(someClass).doSomeThing(captor.capture())

I tried what @mfulton26 suggested, but was getting an error message saying captor.capture() must not be null. and this was what worked for me.

Declared a member variable captor with @Captor annotation,

@Captor private lateinit var captor: ArgumentCaptor<Callback>

and in my @Test,

verify(someClass).doSomething(capture(captor))

Tags:

Mockito

Kotlin