Java 如何创建CloseableHttpResponse对象来帮助测试?

Java 如何创建CloseableHttpResponse对象来帮助测试?,java,mocking,mockito,apache-commons-httpclient,Java,Mocking,Mockito,Apache Commons Httpclient,我试图构造一个模拟对象,在我的一个单元测试中返回,但是没有用于它的构造函数。我发现了这个,但它只会产生一个HttpResponse。构建可关闭HttpResponse的简单方法是什么?我是否需要在测试中调用execute(),然后设置statusLine和实体?这似乎是一种奇怪的方法 以下是我试图模仿的方法: public static CloseableHttpResponse getViaProxy(String url, String ip, int port, String userna

我试图构造一个模拟对象,在我的一个单元测试中返回,但是没有用于它的构造函数。我发现了这个,但它只会产生一个HttpResponse。构建可关闭HttpResponse的简单方法是什么?我是否需要在测试中调用
execute()
,然后设置
statusLine
实体
?这似乎是一种奇怪的方法

以下是我试图模仿的方法:

public static CloseableHttpResponse getViaProxy(String url, String ip, int port, String username,
                                                String password) {
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(
            new AuthScope(ip, port),
            new UsernamePasswordCredentials(username, password));
    CloseableHttpClient httpclient = HttpClients.custom()
            .setDefaultCredentialsProvider(credsProvider).build();
    try {
        RequestConfig config = RequestConfig.custom()
                .setProxy(new HttpHost(ip, port))
                .build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(config);

        LOGGER.info("executing request: " + httpGet.getRequestLine() + " via proxy ip: " + ip + " port: " + port +
                " username: " + username + " password: " + password);

        CloseableHttpResponse response = null;
        try {
            return httpclient.execute(httpGet);
        } catch (Exception e) {
            throw new RuntimeException("Could not GET with " + url + " via proxy ip: " + ip + " port: " + port +
                    " username: " + username + " password: " + password, e);
        } finally {
            try {
                response.close();
            } catch (Exception e) {
                throw new RuntimeException("Could not close response", e);
            }
        }
    } finally {
        try {
            httpclient.close();
        } catch (Exception e) {
            throw new RuntimeException("Could not close httpclient", e);
        }
    }
}
下面是使用PowerMockito的模拟代码:

    mockStatic(HttpUtils.class);
    when(HttpUtils.getViaProxy("http://www.google.com", anyString(), anyInt(), anyString(), anyString()).thenReturn(/*mockedCloseableHttpResponseObject goes here*/)

nvm,我只是通过使用
execute()
对其进行了黑客攻击:


遵循以下步骤可能会有所帮助:

1.模仿它(例如模仿)

2.应用一些规则

when(response.getStatusLine()).thenReturn(new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "FINE!"));
when(entity.getContent()).thenReturn(getClass().getClassLoader().getResourceAsStream("result.txt"));
when(response.getEntity()).thenReturn(entity);
3.使用它

when(httpClient.execute((HttpGet) any())).thenReturn(response);

我想创建一个具体的CloseableHttpResponse,而不是mock,所以我在ApacheHTTP客户端源代码中找到了它

在中,execute的所有返回值如下所示:

return new HttpResponseProxy(response, connHolder);
其中connHolder可以为null

只是一个薄薄的包装物,它可以在支架上关闭。不幸的是,它是包保护的,所以它(不一定)是可见的

我所做的是创建一个“PublicHttpResponseProxy”

必须在包“org.apache.http.impl.execchain”中(!)基本上会将可见性提升到public,并提供带有空连接处理程序的构造函数

现在我可以用

CloseableHttpResponse response = new PublicHttpResponseProxy(basicResponse);

通常的警告适用。由于代理是受包保护的,它不是官方API的一部分,因此您可能正在下赌注,它稍后将不可用。另一方面,它没有太多内容,所以您可以轻松地编写自己的版本。可能会有一些剪切和粘贴,但不会那么糟糕。

这个问题已经问了很久了,但我想提供一个我使用的解决方案

我创建了一个小型类,它扩展了
BasicHttpResponse
类,并实现了
CloseableHttpResponse
接口(它只有一个关闭响应的方法)。由于
BasicHttpResponse
类包含几乎所有内容的setter方法,因此我可以使用以下代码段设置我需要的所有字段:

public static CloseableHttpResponse buildMockResponse() throws FileNotFoundException {
    ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
    String reasonPhrase = "OK";
    StatusLine statusline = new BasicStatusLine(protocolVersion, HttpStatus.SC_OK, reasonPhrase);
    MockCloseableHttpResponse mockResponse = new MockCloseableHttpResponse(statusline);
    BasicHttpEntity entity = new BasicHttpEntity();
    URL url = Thread.currentThread().getContextClassLoader().getResource("response.txt");
    InputStream instream = new FileInputStream(new File(url.getPath()));
    entity.setContent(instream);
    mockResponse.setEntity(entity);
    return mockResponse;
}

我基本上设置了实际代码使用的所有字段。这还包括将模拟响应内容从文件读取到流中。

只需借助现有的BasicHttpResponse类型创建一个测试实现即可:

public class TestCloseableHttpResponse extends BasicHttpResponse implements CloseableHttpResponse {

    public TestCloseableHttpResponse(StatusLine statusline, ReasonPhraseCatalog catalog, Locale locale) {
        super(statusline, catalog, locale);
    }

    public TestCloseableHttpResponse(StatusLine statusline) {
        super(statusline);
    }

    public TestCloseableHttpResponse(ProtocolVersion ver, int code, String reason) {
        super(ver, code, reason);
    }


    @Override
    public void close() throws IOException { }

}

每次你调用该方法时,它不会下载www.test.com的新副本吗?听起来像是一个皮塔在等着咬你。这个还没有投票,但它是智能和干净的,我将使用一个更可靠的服务器,如google.com,它也很轻下载(假设它是完全合法的),而不是建立对象。如果可能的话,你也可以在你的组织内部使用一个内部服务器。这似乎不是在httpclient 5下编译的。“实现CloseableHttpResponse”,但不能模拟CloseableHttpResponse,因为它是最终的。。这就是问题的重点
CloseableHttpResponse response = new PublicHttpResponseProxy(basicResponse);
public static CloseableHttpResponse buildMockResponse() throws FileNotFoundException {
    ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
    String reasonPhrase = "OK";
    StatusLine statusline = new BasicStatusLine(protocolVersion, HttpStatus.SC_OK, reasonPhrase);
    MockCloseableHttpResponse mockResponse = new MockCloseableHttpResponse(statusline);
    BasicHttpEntity entity = new BasicHttpEntity();
    URL url = Thread.currentThread().getContextClassLoader().getResource("response.txt");
    InputStream instream = new FileInputStream(new File(url.getPath()));
    entity.setContent(instream);
    mockResponse.setEntity(entity);
    return mockResponse;
}
public class TestCloseableHttpResponse extends BasicHttpResponse implements CloseableHttpResponse {

    public TestCloseableHttpResponse(StatusLine statusline, ReasonPhraseCatalog catalog, Locale locale) {
        super(statusline, catalog, locale);
    }

    public TestCloseableHttpResponse(StatusLine statusline) {
        super(statusline);
    }

    public TestCloseableHttpResponse(ProtocolVersion ver, int code, String reason) {
        super(ver, code, reason);
    }


    @Override
    public void close() throws IOException { }

}