You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android测试中OkHttp MockWebServer二次调用触发SocketTimeoutException问题

解决MockWebServer同一测试用例二次调用端点超时问题

问题根源

你在setUp方法中仅给MockWebServer入队了一个响应,第一次请求会消耗掉这个响应;当第二次请求发起时,MockWebServer的响应队列已为空,没有可用响应返回,最终触发SocketTimeoutException。

解决方案

1. 提前入队足够数量的响应

如果两次请求需要返回相同的响应,只需在setUp中多次入队同一响应即可:

@Before
fun setUp() {
    hiltRule.inject()
    mockWebServer.start()
    val response = SharedUtil.searchAPIMockWebServerResponseWith200()
    // 入队两次响应,供两次请求分别消费
    mockWebServer.enqueue(response)
    mockWebServer.enqueue(response)
}

也可以在第二次请求发起前,临时入队响应:

@Test
fun testCalls() {
    runBlocking {
        val firstFlow = productRepo.getMatchedProducts("Search")
        firstFlow.collectLatest { outcome ->
            if (outcome is Outcome.Success) {
                println("output one $outcome")
            }
        }

        // 第二次请求前补充入队响应
        mockWebServer.enqueue(SharedUtil.searchAPIMockWebServerResponseWith200())
        val secondFlow = productRepo.getMatchedProducts("Search")
        secondFlow.collectLatest { outcome ->
            if (outcome is Outcome.Success) {
                println("output two $outcome ")
            }
        }
    }
}

2. 使用Dispatcher统一处理重复请求

如果需要对同一端点的所有请求都返回相同响应,推荐使用Dispatcher替代enqueue,无需手动维护响应队列:

@Before
fun setUp() {
    hiltRule.inject()
    mockWebServer.start()
    val successResponse = SharedUtil.searchAPIMockWebServerResponseWith200()
    
    mockWebServer.dispatcher = object : Dispatcher() {
        override fun dispatch(request: RecordedRequest): MockResponse {
            // 根据接口路径匹配返回对应的响应(替换成你的实际接口路径)
            return if (request.path.contains("/products/search")) {
                successResponse
            } else {
                // 非目标接口返回404
                MockResponse().setResponseCode(404)
            }
        }
    }
}

3. 优化协程收集逻辑

你的测试代码中嵌套了collectLatest并使用delay,可能导致协程调度异常。建议改成顺序收集,确保第一次请求完全结束后再发起第二次请求:

@Test
fun testCalls() {
    runBlocking {
        // 先完成第一次请求的收集
        productRepo.getMatchedProducts("Search").collectLatest { outcome ->
            if (outcome is Outcome.Success) {
                println("output one $outcome")
            }
        }

        // 再发起并收集第二次请求
        productRepo.getMatchedProducts("Search").collectLatest { outcome ->
            if (outcome is Outcome.Success) {
                println("output two $outcome ")
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者user1154390

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 00:52:42