Search code examples
junitkotlinmockitokotlinx.coroutines

Mocked suspend function returns null in Mockito


I have a suspending functions that I have mocked, using Mockito but it is returning null

both projects use

'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'

Example 1

here is my test in which the mock is returning null

@Test
fun `when gps not enabled observer is notified`() = runBlocking {
    // arrange
    `when`(suspendingLocationService.getCurrentLocation()).thenReturn(result) // <- when called this returns null

    // act
    presenter.onStartShopButtonClick()

    // assert
    verify(view).observer
    verify(observer).onPrepareShop()
}

I have the below implementation in my presenter

  override suspend fun onStartShopButtonClick() {
    val result = suspendingLocationService.getCurrentLocation() // <- in my test result is null!!!!!!
    view?.apply {
        observer?.onPrepareShop()
        when {
            result.hasGivenPermission == false -> observer?.onStartShop(StoreData(), APIError(APIError.ErrorType.NO_PERMISSION))
            result.hasGPSEnabled == false -> observer?.onStartShop(StoreData(), APIError(APIError.ErrorType.GPS_NOT_ENABLED))
            result.latitude != null && result.longitude != null ->
                storeLocationService.getCurrentStore(result.latitude, result.longitude) { store, error ->
                    observer?.onStartShop(store, error)
                }
        }
    }
}

however I have what I believe to a very similar implementation that is working below

Example 2

The below test does pass and the correct the function does respond with a product

@Test
fun `suspending implementation updates label`() = runBlocking {
    // arrange
    `when`(suspendingProductProvider.getProduct("testString")).thenReturn(product)

    // act
    presenter.textChanged("testString")

    // assert
    verify(view).update(product.name)
}

here is the implementation of the presenter

override suspend fun textChanged(newText: String?) {
    val product = suspendingNetworkProvider.getProduct(newText)
    view?.update(product.name)
}

here is the interface I am mocking

interface SuspendingProductProvider {
    suspend fun getProduct(search: String?): Product
}

what I am not doing in the first example


Solution

  • Mockito has a special support for suspend functions, but in Kotlin 1.3 there were some changes in how coroutines are implemented internally, so older versions of Mockito are no longer recognize suspend methods compiled by Kotlin 1.3. And kotlinx.coroutines use Kotlin 1.3 since version 1.0.0.

    Corresponding support was added to Mockito, but only since version 2.23, so updating your Mockito version will help.