Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

For Apache HttpClient 4.x, create a CloseableHttpResponse in a unit test by mocking its interface with Mockito, then stub the status, entity, and headers your code reads. If the code calls an HTTP client, mock that client too and have it return the prepared response. Use HttpClient 5.x imports only with 5.x code: the packages and response APIs differ.

First, check which HttpClient version you use

In HttpClient 4.x, the typical imports are:

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;

CloseableHttpResponse is an interface in 4.x, extending HttpResponse and Closeable. You cannot instantiate it with new; use a mock or write a custom implementation. For most unit tests, Mockito is the simplest option. See the HttpClient 4.5 API documentation.

HttpClient 5.x uses different packages, including org.apache.hc.client5.http.impl.classic.CloseableHttpResponse and org.apache.hc.core5.http.ClassicHttpResponse. These are not interchangeable with the 4.x types. Confirm the dependency and use its matching imports throughout the production code and test.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a basic 4.x response mock

Stub the methods the code under test actually calls. For example, a status-only test can supply a real status-line object:

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.http.HttpVersion;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.message.BasicStatusLine;

CloseableHttpResponse response = mock(CloseableHttpResponse.class);
when(response.getStatusLine()).thenReturn(
    new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK")
);

Production code can then read response.getStatusLine().getStatusCode(). Add a reason phrase or protocol-version assertion only if your application’s behavior depends on it. Unstubbed Mockito methods generally return defaults—often null for object types—so a call to getEntity() or getStatusLine() may otherwise return null. See Mockito’s documentation for mocking and stubbing behavior.

Add a body and headers

When testing body reading or parsing, use a real HttpEntity such as StringEntity. This exercises actual entity consumption rather than a mock’s canned return values:

import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;

HttpEntity entity = new StringEntity(
    "{"message":"success"}",
    ContentType.APPLICATION_JSON
);
when(response.getEntity()).thenReturn(entity);

For plain text, use ContentType.TEXT_PLAIN. To test a response with no entity, explicitly return null. That differs from an empty entity, which is present but has zero-length content:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
when(response.getEntity()).thenReturn(null); // No entity
when(response.getEntity()).thenReturn(
    new StringEntity("", ContentType.APPLICATION_JSON) // Empty entity
);

Stub the specific header accessor your code uses. Stubbing one method does not populate the others:

import org.apache.http.Header;
import org.apache.http.message.BasicHeader;

when(response.getFirstHeader("Content-Type"))
    .thenReturn(new BasicHeader("Content-Type", "application/json"));

when(response.getHeaders("Set-Cookie"))
    .thenReturn(new Header[] {
        new BasicHeader("Set-Cookie", "session=test")
    });

If production code calls getAllHeaders(), stub that method separately. Avoid mocking every response detail when the test only needs to verify one behavior.

Mock the client when production code calls execute

A response mock alone is not enough if the method under test calls CloseableHttpClient.execute. Inject a mocked client and return the response from the exact overload your code uses:

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.http.client.methods.CloseableHttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;

CloseableHttpClient client = mock(CloseableHttpClient.class);
CloseableHttpResponse response = mock(CloseableHttpResponse.class);

when(client.execute(any(HttpUriRequest.class))).thenReturn(response);

Do not construct a real client inside the class you are unit-testing if your goal is to avoid network access. Constructor injection makes the dependency replaceable in a test. Also ensure that your stub matches the overload actually called: execute(HttpUriRequest) and other execute signatures are distinct methods.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Complete unit-test example

This example tests a class that fetches a body, reads a real entity, and closes the response. The production method checks for a missing entity rather than passing null to the entity-reading utility.

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.HttpVersion;
import org.apache.http.util.EntityUtils;

class ApiClient {
    private final CloseableHttpClient httpClient;

    ApiClient(CloseableHttpClient httpClient) {
        this.httpClient = httpClient;
    }

    String fetch() throws IOException {
        HttpGet request = new HttpGet("https://example.test/items");
        try (CloseableHttpResponse response = httpClient.execute(request)) {
            HttpEntity entity = response.getEntity();
            return entity == null ? "" : EntityUtils.toString(entity);
        }
    }
}

// In a JUnit 5 test:
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;

class ApiClientTest {
    @Test
    void readsBodyAndClosesResponse() throws Exception {
        CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
        CloseableHttpResponse response = mock(CloseableHttpResponse.class);
        when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(response);
        when(response.getStatusLine()).thenReturn(
            new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK")
        );
        when(response.getEntity()).thenReturn(
            new StringEntity("{"result":"ok"}", ContentType.APPLICATION_JSON)
        );

        ApiClient apiClient = new ApiClient(httpClient);

        assertEquals("{"result":"ok"}", apiClient.fetch());
        verify(httpClient).execute(any(HttpUriRequest.class));
        verify(response).close();
    }
}

In a real test file, keep imports at the top of the file rather than interspersing them with class declarations as this compact example does. If your method also checks the status line, the stub above supplies it; if it does not, omit that setup.

Test error paths and response lifecycle

Change the status line to exercise application behavior for particular codes—for example, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 404 Not Found, 429 Too Many Requests, 500 Internal Server Error, or 503 Service Unavailable. The status code does not dictate how your application must handle it; test the contract your code is meant to implement.

For a 204 response, test both the expected status and the no-entity case if that is how the upstream API behaves. A missing entity and a zero-length entity may need different handling. For malformed JSON, use a real entity containing invalid JSON so the parser sees the same kind of input it would in production.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test execution failures by making the client throw, and verify that your method propagates or handles the exception as intended:

when(client.execute(any(HttpUriRequest.class)))
    .thenThrow(new IOException("connection failed"));

To test a body-read failure, configure the entity or its content stream to throw an IOException at the relevant read operation. To test a close failure, Mockito can throw from the void method:

import static org.mockito.Mockito.doThrow;

doThrow(new IOException("close failed")).when(response).close();

Decide from the production contract whether that failure should be propagated, logged, or suppressed. With try-with-resources, if the body-processing operation already throws, a later exception from close() is recorded as a suppressed exception rather than replacing the primary failure. To verify cleanup after a processing failure, assert that the exception is raised and call verify(response).close().

Apache’s HttpClient 4.x quick-start guide emphasizes closing responses: an open response can retain the underlying connection. Try-with-resources is the straightforward way to ensure closure on both normal and exceptional paths.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

HttpClient 5.x: use its own response API

Do not paste 4.x code into a 5.x test. HttpClient 5.x uses org.apache.hc.* packages, different core response types, and different execution APIs. Its CloseableHttpResponse is a concrete compatibility class; its API includes adapt(ClassicHttpResponse), but the current 5.6 API documentation marks adaptation as internal. It is not the default construction technique to recommend for ordinary tests.

For 5.x code using a response handler, test the handler or the client interaction around it rather than insisting on constructing a closeable response. Handler-based execution is generally preferable when the response can be consumed within the callback, because the client manages response-resource deallocation. See the HttpClient 5.x API documentation. If your code explicitly uses classic closeable responses, keep all types and stubs in the 5.x API family.

Mock or use a test HTTP server?

Mock the response and client for a unit test of how your code interprets status, headers, and body. This is fast and lets you exercise unusual outcomes without network variability. A mock cannot prove that actual request serialization, TLS, redirects, connection pooling, proxy behavior, timeouts, streaming, or server headers work correctly. Use a real or embedded test server for those integration concerns.

Troubleshooting

Symptom Likely cause Fix
Cannot instantiate CloseableHttpResponse You are using the HttpClient 4.x interface. Mock it, or provide a custom implementation.
getStatusLine() is null The response mock has no status-line stub. Stub getStatusLine() with a BasicStatusLine.
getEntity() is null unexpectedly An unstubbed object-returning method returns the default null. Return a real entity, or explicitly return null when testing no entity.
The client returns null despite a stub The test stubbed a different execute overload from the one production code calls. Match the exact argument types and overload.
4.x and 5.x types cannot be assigned to each other The imports come from different major versions. Use one API family consistently and inspect the project dependency.
Test passes but response is not closed Closure is not asserted, or the production method fails to close it. Use try-with-resources in production code and verify response.close().

For a typical HttpClient 4.x unit test, mock the client and response, use a real entity for body parsing, stub only the methods the code calls, and verify response closure. Choose a test server instead when the behavior depends on the actual HTTP exchange.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.