Как создать объект CloseableHttpResponse для тестирования?
Я пытаюсь построить объект CloseableHttpResponse, который будет возвращен в одном из моих модульных тестов, но нет конструктора для него, Я нашел этот DefaultHttpResponseFactory, но он только делает HttpResponse. Какой простой способ построить CloseableHttpResponse? Мне нужно вызвать execute()
в моем тесте, а затем установить statusLine
и entity
? Это похоже на странный подход.
Здесь метод, который я пытаюсь высмеять:
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*/)
Ответы
Ответ 1
Выполните следующие действия:
1. Подключить его (например, mockito)
CloseableHttpResponse response = mock(CloseableHttpResponse.class);
HttpEntity entity = mock(HttpEntity.class);
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);
Ответ 2
Я хотел создать конкретный CloseableHttpResponse, а не макет, поэтому я отследил его в исходном коде клиента Apache HTTP.
В MainClientExec все возвращаемые значения из выполнения выглядят следующим образом:
return new HttpResponseProxy(response, connHolder);
где connHolder может быть нулевым.
HttpResponseProxy - это всего лишь тонкая оболочка, которая закрывается на connHolder. К сожалению, он защищен пакетом, поэтому он (обязательно) не виден.
Что я сделал, так это создать "PublicHttpResponseProxy"
package org.apache.http.impl.execchain;
import org.apache.http.HttpResponse;
public class PublicHttpResponseProxy extends HttpResponseProxy {
public PublicHttpResponseProxy(HttpResponse original) {
super(original, null);
}
}
Должно быть в пакете "org.apache.http.impl.execchain" (!) В основном ударяет видимость для публики и предоставляет конструктору нулевой обработчик подключений.
Теперь я могу создать конкретный CloseableHttpResponse с помощью
CloseableHttpResponse response = new PublicHttpResponseProxy(basicResponse);
Применяются обычные оговорки. Поскольку прокси-сервер защищен пакетом, он не является частью официального API, поэтому вы можете перевернуть кости, которые позже будут недоступны. С другой стороны, там не так много, поэтому вы можете просто написать свою собственную версию. Было бы немного вырезания и вставки, но это было бы не так уж плохо.
Ответ 3
Прошло некоторое время с тех пор, как был задан этот вопрос, но я хочу предоставить решение, которое я использовал.
Я создал небольшой класс, который расширяет класс 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;
}
Я в основном устанавливаю все поля, которые используются фактическим кодом. Это также включает чтение фиктивного содержимого ответа из файла в поток.
Ответ 4
nvm, я просто взломал его, используя execute()
:
private CloseableHttpResponse getMockClosesableHttpResponse(HttpResponse response) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse closeableHttpResponse = httpClient.execute(new HttpGet("http://www.test.com"));
closeableHttpResponse.setEntity(response.getEntity());
closeableHttpResponse.setStatusLine(response.getStatusLine());
return closeableHttpResponse;
}