tomaytotomato
tomaytotomato

Reputation: 4028

How to test IOException case in OkHttp?

I am trying to test my codebase in the event OkHttpClient throws an IOException

Code under test

    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

@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");
}

I tried to mock the OkHttpClient and Builder class, however Builder is final, and mockito cannot mock it.

In the constructor of the class under test, you are recommended to create a new instance of OkHttpClient by invoking this

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

I tried to create a wrapper around OkHttpClient but that didn't work either

    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);
        }
    }
}

How can I force okhttpclient to throw an IOException?

Upvotes: 10

Views: 2279

Answers (2)

tomaytotomato
tomaytotomato

Reputation: 4028

In the end the best solution was to leverage OkHttp's MockWebServer

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

Using a scenario where MockWebserver unexpectedly terminates the HTTP connection, causes an IOException scenario

@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");
}

Note: use of AssertJ library in this test

Upvotes: 9

Wojtek
Wojtek

Reputation: 1530

You have a few options:

Upvotes: 1

Related Questions