Search code examples
javamockitopowermockito

How to mock HttpClient class to return different responses


How can I make Mockito return different HttpEntity values in response to different URIs?

The test is going to make multiple HTTP requests (all of them are POST requests) with the mockHttpClient.

HttpEntity httpEntity = EntityBuilder.create().setText(response).build();
PowerMockito.when(response, "getEntity").thenReturn(httpEntity);

And the test itself is designed this way:

CloseableHttpClient client = mockHttpClient(200, HTTP_ENTITY);
runTest();
Mockito.verify(client, Mockito.times(2)).execute(Mockito.any());

For the above test to return different HTTP entities, I tried the following:

CloseableHttpClient client = Mockito.mock(CloseableHttpClient.class);
    Mockito.when(client.execute(new HttpPost("http://127.0.0.1:8000/new/a"))).thenReturn(resp1);
    Mockito.when(client.execute(new HttpPost("http://127.0.0.1:8000/new/a/b"))).thenReturn(resp2);

But I'm unable to build different http entities and get in response based on the URIs in the request.


Solution

  • Thank you mle. Your response helped me understand how to better structure a test. But in this case I'm trying to modify one without any restructuring.

    I thought I ll post my answer here just in case someone else is looking for one.

    Mockito.doAnswer(new Answer<CloseableHttpResponse>() {
      @Override
      public CloseableHttpResponse answer(InvocationOnMock invocation) {
        CloseableHttpResponse httpResponse = Mockito.mock(CloseableHttpResponse.class);
    
        // No change to status code based on endpoints
        Mockito.when(status.getStatusCode()).thenReturn(withResponseCode);
        Mockito.when(httpResponse.getStatusLine()).thenReturn(status);
    
        HttpEntity entity = Mockito.mock(HttpEntity.class);
        Object[] args = invocation.getArguments();
        String endpoint = ((HttpPost) args[0]).getURI().getPath();
        if (endpoint.contains("/a/b")) {
          entity = EntityBuilder.create().setText("something").build();
          Mockito.when(httpResponse.getEntity()).thenReturn(entity);
        } else {
          entity = EntityBuilder.create().setText("something else").build();
          Mockito.when(httpResponse.getEntity()).thenReturn(entity);
        }
        return httpResponse;
      }
    }).when(client).execute(Mockito.any(HttpUriRequest.class)); 
    

    The integration test does is not testing the rest client itself and I don't need knobs and multiple mock clients for different responses. And the above helps me in returning different responses based on the endpoint that is receiving requests.