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

如何在OkHttp中测试IOException抛出的业务场景?

解决方案

你遇到的核心问题是OkHttpClient及其Builder都是final类,Mockito默认不支持mock final类,可通过以下三种方案解决:

方案1:启用Mockito对final类的mock支持

这是改动最小的方案,不需要修改业务代码,仅需调整测试配置和测试代码:

  1. 在测试资源路径src/test/resources下创建目录结构META-INF/mockito-extensions,新增文件org.mockito.plugins.MockMaker,文件内容写入:
mock-maker-inline
  1. 修正你的测试代码,删除提前触发方法调用的多余行:
@Test
void createCustomer_WhenValidRequestAndIOException_ThenThrowAPIException() throws ZeusServiceException, ZeusClientException {
    //Given
    final OkHttpClient okHttpClientMock = mock(OkHttpClient.class, RETURNS_DEEP_STUBS);
    final OkHttpClient.Builder okHttpBuilderMock = mock(OkHttpClient.Builder.class);
    httpClient = new HttpClient(okHttpClientMock, configuration, objectMapper);
    //When
    when(okHttpClientMock.newBuilder()).thenReturn(okHttpBuilderMock);
    when(okHttpBuilderMock.build()).thenReturn(okHttpClientMock);
    when(okHttpClientMock.newCall(any())).thenThrow(IOException.class);
    // 校验抛出异常
    assertThatThrownBy(() -> httpClient.createCustomer(request))
        .isInstanceOf(ApiException.class)
        .hasCauseInstanceOf(IOException.class);
}

注意:你之前的断言hasMessage("IO Error from API")是错误的,因为你抛出的ApiException的message是e.getMessage(),也就是IOException的消息,不是日志里打印的内容,建议改为校验异常类型或者cause。

方案2:使用OkHttp官方的MockWebServer(更推荐)

这是OkHttp官方提供的测试组件,不需要mock任何类,更贴近真实运行场景:

  1. 引入MockWebServer依赖(以Gradle为例):
testImplementation 'com.squareup.okhttp3:mockwebserver:你的okhttp版本号'
  1. 编写测试代码:
@Test
void createCustomer_WhenValidRequestAndIOException_ThenThrowAPIException() throws IOException {
    // 启动MockWebServer
    MockWebServer mockWebServer = new MockWebServer();
    // 配置收到请求后直接断开连接,触发IOException
    mockWebServer.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST));
    mockWebServer.start();
    
    // 将你的configuration中的API base地址改为mockWebServer的地址
    when(configuration.getApiBaseUrl()).thenReturn(mockWebServer.url("/").toString());
    // 初始化HttpClient,使用真实的OkHttpClient实例即可
    httpClient = new HttpClient(new OkHttpClient(), configuration, objectMapper);
    
    // 断言
    assertThatThrownBy(() -> httpClient.createCustomer(request))
        .isInstanceOf(ApiException.class)
        .hasCauseInstanceOf(IOException.class);
    
    // 关闭服务
    mockWebServer.shutdown();
}

方案3:抽象Http客户端接口解耦

如果要彻底降低业务代码和OkHttp的耦合,可自行抽象一层Http客户端接口:

  1. 定义接口:
public interface CustomHttpClient {
    Response execute(Request request) throws IOException;
}
  1. 实现OkHttp的适配类:
public class OkHttpCustomClient implements CustomHttpClient {
    private final OkHttpClient okHttpClient;
    
    public OkHttpCustomClient(OkHttpClient okHttpClient) {
        this.okHttpClient = okHttpClient.newBuilder().build();
    }
    
    @Override
    public Response execute(Request request) throws IOException {
        return okHttpClient.newCall(request).execute();
    }
}
  1. 你的业务HttpClient类改为依赖CustomHttpClient接口,测试时直接mock接口抛IOException即可,不需要处理OkHttp的final类问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 23:36:00