使用Mockito模拟Apache HTTPClient

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Mockito模拟Apache HTTPClient相关的知识,希望对你有一定的参考价值。

我正在尝试模拟Apache HttpClient接口,以便模拟下面提到的一个方法来返回一个存根的JSON对象作为响应。

HttpResponse response = defaultHttpClient.execute(postRequest); 

有人可以通过一些示例代码建议如何实现这一目标吗?非常感谢您的帮助。

谢谢

答案

以下是我使用Mockito和Apache HttpBuilder测试代码的方法:

被测班:

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

测试:

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

}

你认为伙计们,我需要改进什么? (是的,我知道,评论。这是我从Spock背景中得到的东西:D)

另一答案

在您的单元测试类中,您需要模拟defaultHttpClient

@Mock
private HttpClient defaultHttpClient;

然后你告诉mockito(例如在@Before方法中)通过以下方式实际创建你的模拟:

MockitoAnnotations.initMocks(YourTestClass);

然后在您的测试方法中定义execute()方法应返回的内容:

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

你可以看看HttpClientMock,我为内部项目编写了它,但后来决定开源。它允许您使用流畅的API定义模拟行为,然后验证许多调用。例:

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

httpClientMock.verify().get("/login?user=john").called();
另一答案

您可以使用PowerMockito轻松完成此操作,PowerMockito还可以轻松地模拟最终/静态方法,私有方法和匿名类。这是模拟http请求的示例代码。 JSON_STRING_DATA是您要从execute方法获取的任何字符串。

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

以上是关于使用Mockito模拟Apache HTTPClient的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mockito 时,模拟和间谍有啥区别?

如何使用 mockito 模拟方法?

Junit/Mockito:选择使用模拟或集成测试运行测试

使用 Mockito 模拟静态方法

如何使用 Mockito 模拟受保护的方法?

如何使用 Mockito 模拟内部类实例