android - 如何在函数中测试 Kotlin 协程?
问题描述
我正在创建一个库,并且我正在使用 Retrofit 和一个调用适配器,它给了我一个 Deferred<> 值。
在我调用的代码中的一个函数中,在launch {}
其中我调用try-catch
了值和可能的异常 - 为不同的结果调用不同的回调。
我在测试协程中找到的资源都是关于测试挂起函数的,并且runBlocking {}
是解决所有问题的方法。除了我不是
我做了一个简单的例子
@Mock
val mockListener: DoSomething.Listener = mock()
@Test
fun testSomething() {
val doer = DoSomething(mockListener)
runBlocking {
doer.doIt()
verify(mockListener).listen(any())
}
}
class DoSomething(val listener: Listener) {
interface Listener {
fun listen(s: String)
}
fun doIt() {
launch {
listener.listen(theThing().await())
}
}
private fun theThing(): Deferred<String> {
return async {
delay(5, TimeUnit.SECONDS)
return@async "Wow, a thing"
}
}
}
我想要的是实际运行所有功能。测试至少需要 5 秒,但它只在几毫秒内运行完代码。它不会阻塞。
我试过添加
runBlocking {
launch {
// doer.doIt()
}.joinChildren()
}
和类似的做法,但我只是无法让测试在测试完成之前真正等待我在另一个课程中的启动完成。放置verify(...)
外部runBlocking
也会使测试失败,这是应该的。
任何输入、帮助者、良好实践等都将受到赞赏!
解决方案
您可以为您的函数显式提供 CoroutineContext doIt()
:
fun doIt(context: CoroutineContext = DefaultDispatcher) {
launch(context) {
listener.listen(theThing().await()
}
}
使用此参数,您可以轻松更改协程上下文 - 在您的测试代码中,您使用阻塞上下文:
runBlocking {
doer.doIt(coroutineContext)
}
顺便说一句:您不需要使用launch
and async
。有了launch
你在一个suspendable
上下文中,你不需要theThing()
异步运行。特别是如果您await()
在下一步中调用:
fun doIt(context: CoroutineContext = DefaultDispatcher) {
launch(context) {
listener.listen(theThing())
}
}
private suspend fun theThing(): String {
delay(5, TimeUnit.SECONDS)
return "Wow, a thing"
}
推荐阅读
- android - TopAppBar 与 Navigation 集成的脚手架
- angular - 角度迁移“路径”消息
- sql-server - 有没有办法从 SQL Server 中的表中删除重复项?
- web-scraping - 使用 ImportXML 从受密码保护的网站上抓取价格
- sql - 向 SELECT 语句添加虚拟行
- r - 使用带有glue_data 的数据框列名
- c - 是否可以在以后的循环迭代中增加模运算符?
- java - 如何判断一段java代码是否是heap-allocation-free的?
- twilio - 无论实际结果如何,Twilio 始终返回“进行中”
- python - 如何在 python 测试中模拟 subprocess.check_call 异常