Mocking Apache HTTPClient using Mockito

流过昼夜 提交于 2019-11-30 12:38:19

问题


I'm trying to mock Apache HttpClient Interface in order to mock one of its methods mentioned below to return a stubbed JSON object in response.

HttpResponse response = defaultHttpClient.execute(postRequest); 

Could somebody be able to suggest how to achieve this with some sample code? Your help would be greatly appreciated.

Thanks


回答1:


Here is what I did to test my code using Mockito and Apache HttpBuilder:

Class under test:

import java.io.BufferedReader;
import java.io.IOException;

import javax.ws.rs.core.Response.Status;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class StatusApiClient {
private static final Logger LOG = LoggerFactory.getLogger(StatusApiClient.class);

    private String targetUrl = "";
    private HttpClient client = null;
    HttpGet httpGet = null;

    public StatusApiClient(HttpClient client, HttpGet httpGet) {
        this.client = client;
        this.httpGet = httpGet;
    }

    public StatusApiClient(String targetUrl) {
        this.targetUrl = targetUrl;
        this.client = HttpClientBuilder.create().build();
        this.httpGet = new HttpGet(targetUrl);
    }

    public boolean getStatus() {
        BufferedReader rd = null;
        boolean status = false;
        try{
            LOG.debug("Requesting status: " + targetUrl);


            HttpResponse response = client.execute(httpGet);

            if(response.getStatusLine().getStatusCode() == Status.OK.getStatusCode()) {
                LOG.debug("Is online.");
                status = true;
            }

        } catch(Exception e) {
            LOG.error("Error getting the status", e);
        } finally {
            if (rd != null) {
                try{
                    rd.close();
                } catch (IOException ioe) {
                    LOG.error("Error while closing the Buffered Reader used for reading the status", ioe);
                }
            }   
        }

        return status;
    }
}

Test:

import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.HttpHostConnectException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class StatusApiClientTest extends Mockito {

    @Test
    public void should_return_true_if_the_status_api_works_properly() throws ClientProtocolException, IOException {
        //given:
        HttpClient httpClient = mock(HttpClient.class);
        HttpGet httpGet = mock(HttpGet.class);
        HttpResponse httpResponse = mock(HttpResponse.class);
        StatusLine statusLine = mock(StatusLine.class);

        //and:
        when(statusLine.getStatusCode()).thenReturn(200);
        when(httpResponse.getStatusLine()).thenReturn(statusLine);
        when(httpClient.execute(httpGet)).thenReturn(httpResponse);

        //and:
        StatusApiClient client = new StatusApiClient(httpClient, httpGet);

        //when:
        boolean status = client.getStatus();

        //then:
        Assert.assertTrue(status);
    }

    @Test
    public void should_return_false_if_status_api_do_not_respond() throws ClientProtocolException, IOException {
        //given:
        HttpClient httpClient = mock(HttpClient.class);
        HttpGet httpGet = mock(HttpGet.class);
        HttpResponse httpResponse = mock(HttpResponse.class);
        StatusLine statusLine = mock(StatusLine.class);

        //and:
        when(httpClient.execute(httpGet)).thenThrow(HttpHostConnectException.class);

        //and:
        StatusApiClient client = new StatusApiClient(httpClient, httpGet);

        //when:
        boolean status = client.getStatus();

        //then:
        Assert.assertFalse(status);
    }

}

What do you think folks, do I need to improve something? (Yeah, I know, the comments. That is something I brought from my Spock background :D)




回答2:


In your unit test class you need to mock defaultHttpClient:

@Mock
private HttpClient defaultHttpClient;

Then you tell mockito (for example in @Before method) to actually create your mocks by:

MockitoAnnotations.initMocks(YourTestClass);

Then in your test method you define what execute() method should return:

when(defaultHttpClient.execute(any()/* or wahtever you want here */)).thenReturn(stubbed JSON object);



回答3:


You can look at HttpClientMock, I wrote it for internal project but later decided to open source. It allows you to define mock behavior with fluent API and later verify a number of made calls. Example:

HttpClientMock httpClientMock = new 
HttpClientMock("http://localhost:8080");
httpClientMock.onGet("/login?user=john").doReturnJSON("{permission:1}");

httpClientMock.verify().get("/login?user=john").called();



回答4:


You can do this easily using PowerMockito which can also mock final/static methods, private methods and anonymous classes easily. Here's the sample code for mocking http request. JSON_STRING_DATA is any string which you want to get from execute method.

PowerMockito.mockStatic(DefaultHttpClient.class);
    HttpClient defaultHttpClientMocked =  PowerMockito.mock(DefaultHttpClient.class);        
    PowerMockito.when(defaultHttpClientMocked.execute(Mockito.any(HttpPost.class))).thenReturn(createMockedHTTPResponse(JSON_STRING_DATA));



回答5:


There is a nicer way to do this without having to add PowerMock as yet another dependency. Here you only need an extra constructor taking HTTPClient as an argument and Mockito. In this example I'm creating a custom health check (Spring Actuator) and I need to mock the HTTPClient for unit testing.

Libs: JUnit 5, Spring Boot 2.1.2 and Mockito 2.

Component:

@Component
public class MyHealthCheck extends AbstractHealthIndicator {

    HttpClient httpClient;

    public MyHealthCheck() { 
        httpClient = HttpClientBuilder.create().build();
    }

    /** 
    Added another constructor to the class with an HttpClient argument.
    This one can be used for testing
    */ 
    public MyHealthCheck(HttpClient httpClient) { 
        this.httpClient = httpClient; 
    }

    /**
    Method to test 
    */ 
    @Override
    protected void doHealthCheck(Builder builder) throws Exception {

        //
        // Execute request and get status code
        HttpGet request = new HttpGet("http://www.SomeAuthEndpoint.com");
        HttpResponse response = httpClient.execute(request);

        //
        // Update builder according to status code
        int statusCode = response.getStatusLine().getStatusCode();
        if(statusCode == 200 || statusCode == 401) {
            builder.up().withDetail("Code from service", statusCode);
        } else {
            builder.unknown().withDetail("Code from service", statusCode);
        }
    }
}

Test method:

Note that here we use Mockito.any(HttpGet.class)

private static HttpClient httpClient;
private static HttpResponse httpResponse;
private static StatusLine statusLine;

@BeforeAll
public static void init() {
    //
    // Given
    httpClient = Mockito.mock(HttpClient.class);
    httpResponse = Mockito.mock(HttpResponse.class);
    statusLine = Mockito.mock(StatusLine.class);
}


@Test
public void doHealthCheck_endReturns401_shouldReturnUp() throws Exception {

    //
    // When
    when(statusLine.getStatusCode()).thenReturn(401);
    when(httpResponse.getStatusLine()).thenReturn(statusLine);
    when(httpClient.execute(Mockito.any(HttpGet.class))).thenReturn(httpResponse);

    //
    // Then
    MyHealthCheck myHealthCheck = new MyHealthCheck(httpClient);
    Health.Builder builder = new Health.Builder();
    myHealthCheck.doHealthCheck(builder);
    Status status = builder.build().getStatus();
    Assertions.assertTrue(Status.UP == status);
}


来源:https://stackoverflow.com/questions/20542361/mocking-apache-httpclient-using-mockito

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!