2

I have a retrofit service

interface Service {
    @PUT("path")
    suspend fun dostuff(@Body body: String)
}

It is used in android view model.

class VM : ViewModel(private val service: Service){
   private val viewModelJob = Job()
   private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

   val state = MutableLiveData<String()

   init {
      uiScope.launch { 
         service.doStuff()
         state.value = "lol"
      }
   }

   override fun onCleared(){
      viewModelJob.cancel()
   }
}

I would like to write a test for the cancelling of the view model. This will be done mocking service and delaying so that the co routine does not complete. Whilst blocking, we invoke onCleared to cancel the co routine. This should prevent state getting set...

@Test
fun `on cleared - cancels request`() = runBlocking {
    //given
    `when`(service.doStuff()).thenAnswer { launch { delay(1000) } }

    val vm = ViewModel(service)
    // when
    vm.cleared()

    //then
    assertThat(vm.state, nullValue())
}

However it seems that vm.state always gets set??? What is the best way to test when clearing a scope that a co routine gets cancelled?

fergdev
  • 963
  • 1
  • 13
  • 27

1 Answers1

3

The problem here is in thenAnswer { launch { delay(1000) } }, which effectively makes your doStuff method look like that:

suspend fun doStuff() {
  launch { delay(1000) } 
}

As you can see, this function does not actually suspend, it launches a coroutine and returns immediately. What would actually work here is thenAnswer { delay(1000) }, which does not work, because there is no suspend version of thenAnswer in Mockito (as far as I know at least).

I would recommend to switch to Mokk mocking library, which supports kotlin natively. Then you can write coEvery { doStuff() } coAnswers { delay(1000) } and it will make your test pass (after fixing all the syntax errors ofc).

esentsov
  • 6,372
  • 21
  • 28
  • 1
    There is a way to mock suspend fun in mockito-kotlin. Use `onBlocking`. However I'm not yet sure how reliable is the coroutine support in all testing libraries. Even the official JetBrains kotlinx-coroutines-test lib is still experimental. – WindRider Dec 12 '19 at 06:21