KMM单元测试中CoroutineScope.launch内Ktor client请求挂起卡死问题
问题根因
该问题属于测试场景的配置遗漏,并非框架本身的bug,核心原因有两点:
- 你的测试函数是普通非挂起函数,未对自定义
CoroutineScope启动的协程做生命周期绑定和等待逻辑。Dispatchers.Unconfined会在当前测试线程执行协程直到第一个挂起点,client.get触发挂起后,测试线程无后续等待逻辑,直接进入测试结束流程,导致请求永远等不到恢复执行的时机,表现为卡死。 - 常规单元测试默认不会等待未绑定测试生命周期的异步任务执行完成,iOS模拟器是应用运行环境,进程不会主动终止,会等待协程恢复,因此运行正常。
解决方案
1. 引入协程测试依赖
在commonTest的依赖配置中添加与项目协程版本匹配的kotlinx-coroutines-test依赖。
2. 重构测试代码
使用协程测试库提供的runTest包裹整个测试逻辑,所有协程操作都会绑定到测试生命周期,测试会自动等待所有异步任务执行完成后再结束:
@ExperimentalCoroutinesApi @Test fun testExample() = runTest { // 自定义作用域传入测试调度器,和测试生命周期绑定 val scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler)) val requestJob = scope.launch { val client = HttpClient { BrowserUserAgent() // JVM端测试可显式指定OkHttp引擎,避免默认引擎的调度兼容问题 } val response : HttpResponse = client.get("https://google.com") println("Response: $response") fail("This test should fail") } // 显式等待协程执行完成 requestJob.join() }
补充说明
如果业务逻辑必须使用自定义协程作用域,仅需要在测试环境下将作用域的调度器替换为测试库提供的UnconfinedTestDispatcher/StandardTestDispatcher即可,生产环境可保持原有的newSingleThreadContext()配置不受影响。
内容的提问来源于stack exchange,提问作者Matt.M
相关产品推荐
相关产品推荐

