1

我有改装服务

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

它用于android视图模型。

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()
   }
}

我想写一个取消视图模型的测试。这将通过模拟服务和延迟来完成,以使 co 例程无法完成。在阻塞的同时,我们调用 onCleared 来取消 co 例程。这应该防止状态被设置...

@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())
}

但是似乎 vm.state 总是被设置???清除协同例程被取消的范围时,最好的测试方法是什么?

4

1 回答 1

3

这里的问题在于thenAnswer { launch { delay(1000) } },它有效地使您的doStuff方法看起来像这样:

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

正如你所看到的,这个函数实际上并没有挂起,它启动一个协程并立即返回。在这里实际可行的是thenAnswer { delay(1000) },这是行不通的,因为thenAnswer在 Mockito 中没有挂起版本(至少据我所知)。

我建议切换到原生支持kotlin的 Mokk 模拟库。然后你就可以写coEvery { doStuff() } coAnswers { delay(1000) }了,它会让你的测试通过(在修复了c的所有语法错误之后)。

于 2019-09-11T08:43:52.403 回答