1

我的 KMM 项目测试在新范围内异步启动的 ktor 客户端请求时遇到问题。出于测试目的,我Dispatchers.Unconfined作为新范围的上下文传入(在我正在使用的实际生产代码中newSingleThreadContext())。

我在下面创建了一个非常简化的悬挂 ktor 请求版本:

@ExperimentalCoroutinesApi
@Test
fun testExample(): Unit {
    val scope = CoroutineScope(Dispatchers.Unconfined)
    scope.launch {
        val client = HttpClient { BrowserUserAgent() }

        // This line hangs
        val response : HttpResponse = client.get("https://google.com")

        // Will never get here
        println("Response: $response")
        fail("This test should fail")
    }
}

请注意,如果您不在 CoroutineScope.launch 中调用,那么它可以正常工作。然后挂起/冻结仅在 CoroutineScope.launch 中调用时发生。同样,这是一个极其简化的示例,但在我的实际代码中,以这种方式设置它的原因是,我可以在最终发出 ktor 请求之前在后台线程中处理一些数据 - 因此是 CoroutineScope.launch。另请注意,我的代码在 iOS 模拟器上运行时似乎运行良好。它仅在作为单元测试运行时挂起

我是否遗漏了一些东西来完成这项工作,或者这是一个错误?

4

1 回答 1

0

我的解决方案最终是在 runBlocking() 范围内运行我的测试,并将其注入coroutineContext到我的类中以在运行 CoroutineScope.launch() 时使用。

object RequestService {
  private val requestContext = newSingleThreadContext("request")
  var testContext by AtomicReference<CoroutineContext?>(null)

  fun makeRequest(block : () -> Unit) {
    CoroutineScope.launch(testContext ?: requestContext) {
      block()
    }
  }
}

@Test
fun testExample() = runBlocking {
    RequestService.testContext = this.coroutineContext
    RequestService.makeRequest() {
        println("Running Ktor coroutine test")
        val client = HttpClient { BrowserUserAgent() }

        // This line doesn't hang anymore when running within runBlocking coroutineContext
        val response : HttpResponse = client.get("https://google.com")
        println("Response: $response")
    }
    println("Finished running Ktor coroutine test")
}

希望这有助于尝试创建跨平台可测试服务的其他人。感谢Aleksei的评论帮助我到达那里。

于 2021-11-17T20:05:07.030 回答