Unit test for Kotlin lambda callback

10,923

Solution 1

To test the lambdas behavior, the underlayingApi has to be mocked where the lambda is invoked via the InvoactionOnMock object like this.

    `when`(underlayingApi.post(eq("some/rest/url"),
                               any())).thenAnswer {
        val argument = it.arguments[1]
        val completion = argument as ((rawResult: String?, exception: Exception?) -> Unit)
        completion.invoke("result", null)
    }

This leads to the invocation of the callback within the object under test. Now to check if the callback out of the object under test is working verify it like that.

    objUnderTest.loadData(id,
                          { json, exception ->
                              assert....
                          })

Solution 2

Building on Martin's answer, here is my approach without lint warnings:

import com.nhaarman.mockito_kotlin.*

@Test
fun loadData() {
    val mockUnderlyingApi: UnderlayingApi = mock()
    val underTest = ClassBeingTested()
    underTest.underlayingApi = mockUnderlyingApi

    whenever(mockUnderlyingApi.post(eq("some/rest/url"), any())).thenAnswer {
        val completion = it.getArgument<((rawResult: String?, exception: Exception?) -> Unit)>(1)
        completion.invoke("result", null)
    }

    underTest.loadData(0L,
            { jsonElement, exception ->
                // Check whatever you need to check
                // on jsonElement an/or exception
            })
}
Share:
10,923

Related videos on Youtube

Martin Mlostek
Author by

Martin Mlostek

Updated on June 15, 2022

Comments

  • Martin Mlostek
    Martin Mlostek almost 2 years

    Let's say we have the following function to test

    fun loadData(dataId: Long, completion: (JsonElement?, Exception?) -> Unit) {
        underlayingApi.post(url = "some/rest/url",
                completion = { rawResult, exception ->
                    val processedResult = processJson(rawResult)
                    completion(processedResult, exception)
                })
    }
    

    It's clear to me how to mock, inject, stub and verify the calls to underlayingApi.

    How to verify the result returned via completion(processedResult, exception)?

  • w3bshark
    w3bshark about 6 years
    With this you may get an "Unchecked Cast" lint warning. To prevent this, you may use the getArgument() function instead. For example: val argument = it.getArgument<((rawResult: String?, exception: Exception?) -> Unit)>(1)
  • Täg
    Täg over 5 years
    Thanks for the most important line import com.nhaarman.mockito_kotlin.*. Here is the library github : github.com/nhaarman/mockito-kotlin. With the 2.1.0 version, just needed to change the import to import com.nhaarman.mockitokotlin2.*
  • Beulah Ana
    Beulah Ana over 4 years
    any() throws InvalidUseOfMatchersException