【发布时间】:2018-05-16 03:38:16
【问题描述】:
我正在我的 Android 应用程序中测试 Kotlin 协程,并且我正在尝试进行以下单元测试
@Test fun `When getVenues success calls explore venues net controller and forwards result to listener`() =
runBlocking {
val near = "Barcelona"
val result = buildMockVenues()
val producerJob = produce<List<VenueModel>>(coroutineContext) { result.value }
whenever(venuesRepository.getVenues(eq(near))) doReturn producerJob // produce corooutine called inside interactor.getVenues(..)
interactor.getVenues(near, success, error) // call to real method
verify(venuesRepository).getVenues(eq(near))
verify(success).invoke(argThat {
value == result.value
})
}
交互器方法如下
fun getVenues(near: String, success: Callback<GetVenuesResult>,
error: Callback<GetVenuesResult>) =
postExecute {
repository.getVenues(near).consumeEach { venues ->
if (venues.isEmpty()) {
error(GetVenuesResult(venues, Throwable("No venues where found")))
} else {
success(GetVenuesResult(venues))
}
}
}
postExecute{..} 是 BaseInteractor 上的一个方法,它通过使用来自 kotlin android 协程库的 launch(UI) 协程的自定义 Executor 在 ui 线程中执行函数
fun <T> postExecute(uiFun: suspend () -> T) =
executor.ui(uiFun)
那么repository.getVenues(..)函数也是使用produce(CommonPool) {}返回ProducerJob的协程
问题在于,交互函数中的成功回调似乎没有按照
verify(success).invoke(argThat {
value == result.value
})
但是,我在调试时确实看到交互器函数中的执行到达consumeEach 内的if (venues.isEmpty()) 行,但随后从那里退出并继续测试,显然在验证成功回调时失败。
我对协程有点陌生,所以任何帮助都将不胜感激。
【问题讨论】:
-
根据非阻塞/异步的性质,作为测试验证一部分的任何异步调用是否可能会失败/通过?也许在
runBlocking {}语句之外进行验证? -
是的,我知道存储库上的可挂起函数本质上是异步的,但请注意,我在测试中使用 runBlocking 协程,据我了解,它使在其中调用的可挂起函数运行在当前线程上?不过可能是我错了
-
我怀疑调用线程被阻塞了,但不是runBlocking中的协程本身。 runBlocking 就像一个 Thread.join() 调用,从文档不得不说 - “如果我们将它包装到 runBlocking {} 中,我们可以使用延迟,它启动一个协程并等待它完成:”。我会放置一些系统时间戳记录来查看何时进行调用 - 这也将验证可挂起的函数调用是否按预期工作。
标签: android unit-testing kotlin kotlinx.coroutines