【问题标题】:Android Mockito Kotlin coroutine test cancelAndroid Mockito Kotlin 协程测试取消
【发布时间】:2019-09-10 21:31:31
【问题描述】:

我有改装服务

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 似乎总是被设置???清除协同例程被取消的范围时,最好的测试方法是什么?

【问题讨论】:

  • 状态将设置在init,所以它永远不可能是null

标签: android kotlin mockito kotlin-coroutines mockito-kotlin


【解决方案1】:

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

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

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

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

【讨论】:

  • 有一种方法可以在 mockito-kotlin 中模拟暂停乐趣。使用onBlocking。但是我还不确定所有测试库中的协程支持有多可靠。甚至官方的 JetBrains kotlinx-coroutines-test 库仍然是实验性的。
猜你喜欢
  • 1970-01-01
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 2019-08-23
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
  • 2021-10-02
相关资源
最近更新 更多