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
相关产品推荐
相关产品推荐

