【问题标题】:How to test IOException case in OkHttp?如何在 OkHttp 中测试 IOException 案例?
【发布时间】:2021-10-24 00:18:16
【问题描述】:

我正在尝试在 OkHttpClient 抛出 IOException 的情况下测试我的代码库

正在测试的代码

    try (var response = okHttpClient.newCall(request).execute()) {
        return response;
    } catch (final IOException e) {
        log.error("IO Error from API", e);
        throw new ApiException(e.getMessage(), e);
    }

测试

@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);
    final var result = httpClient.createCustomer(request);

    assertThatThrownBy(() -> httpClient.createCustomer(request))
        .isInstanceOf(ApiException.class)
        .hasMessage("IO Error from API");
}

我试图模拟 OkHttpClientBuilder 类,但是 Builder 是最终的,mockito 无法模拟它。

在被测类的构造函数中,建议通过调用 this 来创建 OkHttpClient 的新实例

        this.okHttpClient = okHttpClient.newBuilder().build();

我尝试围绕 OkHttpClient 创建一个包装器,但这也不起作用

    public class OkHttpClientWrapper extends OkHttpClient {

        private OkHttpClient okHttpClient;

        public OkHttpClientWrapper(final OkHttpClient okHttpClient) {
            this.okHttpClient = okHttpClient;
        }

        @Override
        public OkHttpClient.Builder newBuilder() {
            return new Builder(okHttpClient);
        }
    }
}

如何强制 okhttpclient 抛出 IOException?

【问题讨论】:

  • 你有没有研究过 PowerMockito 来模拟最终课程?
  • 是的,但人们说 PowerMockito 是邪恶的stackoverflow.com/questions/30162200/why-not-powermock
  • 也许为OkHttpClient 创建一个Factory,然后模拟Factory
  • 尽管 PowerMock 是邪恶的,并且 2021 年对单元测试 RESTful 端点的回答是改用 github.com/square/okhttp/tree/master/mockwebserver 之类的东西,但这并没有改变这一事实。跨度>
  • @GhostCat 确实在 MockWebServer 中有一种方法可以模拟关闭/终止的连接,它涵盖了测试场景。请查看提交的答案

标签: java mockito okhttp


【解决方案1】:

最后最好的解决方案是利用 OkHttp 的MockWebServer

https://github.com/square/okhttp/tree/master/mockwebserver

使用 MockWebserver 意外终止 HTTP 连接的场景,导致 IOException 场景

@Test
void createCustomer_WhenValidRequestAndServerTerminatesConnection_ThenThrowIOException() throws ZeusServiceException, ZeusClientException {

    //Given
    final CreateCustomerRequest request = CreateCustomerRequest.builder().build();

    //When
    mockWebServer.enqueue(new MockResponse()
        .setBody(new Buffer().write(new byte[4096]))
        .setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY));

    assertThatThrownBy(() -> httpClient.createCustomer(request))
        .isInstanceOf(IOException.class)
        .hasMessage("unexpected end of stream");
}

注意:本次测试使用 AssertJ 库

【讨论】:

    【解决方案2】:

    你有几个选择:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-22
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      • 2011-08-05
      • 1970-01-01
      • 2020-02-11
      相关资源
      最近更新 更多