3

I am trying to write unit test cases for my HTTP Client and would like to use mockito to mock the responses received from the server.

public HttpResponse postRequest(String uri, String body) throws IOException {
        HttpResponse response;
        String url = baseUrl + uri;
        try (CloseableHttpClient httpClient = HttpClientBuilder.create()
                .build()) {
            HttpPost post = new HttpPost(url);
            post.setEntity(new StringEntity(body));
            post.setHeader(AUTHORIZATION_HEADER, authorization);
            post.setHeader(CONTENTTYPE_HEADER, APPLICATION_JSON);
            post.setHeader(ACCEPT_HEADER, APPLICATION_JSON);

            response = httpClient.execute(post);
        } catch (IOException e) {
            System.out.println("Caught an exception" + e.getMessage().toString());
            logger.error("Caught an exception" + e.getMessage().toString());
            throw e;
        }
        return response;
    }

My test class is as follows. I am unable to figure out how I should send my response body.

public class HTTPRequestTest extends Mockito {
    private String body = "{a:b}";

    @Test
    public void xyz throws Exception {
        HttpClient httpClient = mock(HttpClient.class);
        HttpPost httpPost = mock(HttpPost.class);
        HttpResponse httpResponse = mock(HttpResponse.class);
        StatusLine statusLine = mock(StatusLine.class);

        when(httpClient.execute(httpPost)).thenReturn(body);
    }
}
Nir Levy
  • 12,750
  • 3
  • 21
  • 38
user1692342
  • 5,007
  • 11
  • 69
  • 128

3 Answers3

9

Using PowerMockito : First annotate your test class

@RunWith(PowerMockRunner.class)

@PrepareForTest(HttpClientBuilder.class)

then your test method can be something like:

  @Test
public void xyz() throws Exception {
    HttpClientBuilder mockClientBuilder = PowerMockito.mock(HttpClientBuilder.class);
    CloseableHttpClient mockHttpClient = PowerMockito.mock(CloseableHttpClient.class);
    CloseableHttpResponse mockResponse = PowerMockito.mock(CloseableHttpResponse.class);
    PowerMockito.mockStatic(HttpClientBuilder.class);

    PowerMockito.when(HttpClientBuilder.class, "create").thenReturn(mockClientBuilder);
    PowerMockito.when(mockClientBuilder.build()).thenReturn(mockHttpClient);
    PowerMockito.when(mockHttpClient.execute(any(HttpPost.class))).thenReturn(mockResponse);

    HttpResponse response = classUnderTest.postRequest("uri", "body");
    //assertResponse 
}
Rafa M.J.
  • 91
  • 1
  • 3
2

The problem is that your HttpClient mock isn't being used in your unit test.

Your postRequest function creates a new HttpClient using this method:

HttpClientBuilder.create().build()

HttpClientBuilder instantiates a new HttpClient, which is a totally separate instance of HttpClient than the mock you create in your unit test. Unfortunately, there isn't an easy way to test your code as written because Mockito can't mock static methods (like HttpClientBuilder.create). See this post for more discussion of this problem and possible workarounds.

To summarize that post, your options are to either rewrite your code so you can inject a mock more easily, or switch to a mocking framework that can mock static methods (like PowerMock).

Community
  • 1
  • 1
0

As suggested in other answers, PowerMock is definitely an option here to mock static methods (in your case HttpClientBuilder.create().build()), however, for your particular instance, you can also resolve the issue by moving the instantiation of the HttpClient out of your doPost method and declare it as instance variable.

@Mock
CloseableHttpClient httpClient = HttpClientBuilder.create().build()

This way when you mock using Mockito, it will be a mocked object. In JUnit5, this can be done by using @Mock above the CloseableHttpClient declaration and then initializing all mocks in the setup method.

Gaurav Sachdeva
  • 652
  • 1
  • 10
  • 23