Java 使用 Mockito 模拟 Apache HTTPClient
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20542361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mocking Apache HTTPClient using Mockito
提问by Global Dictator
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.
我正在尝试模拟 Apache HttpClient 接口,以便模拟下面提到的方法之一,以返回一个存根 JSON 对象作为响应。
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
谢谢
回答by Flying Dumpling
In your unit test class you need to mock defaultHttpClient
:
在您的单元测试类中,您需要模拟defaultHttpClient
:
@Mock
private HttpClient defaultHttpClient;
Then you tell mockito (for example in @Before
method) to actually create your mocks by:
然后你告诉 mockito(例如在@Before
方法中)通过以下方式实际创建你的模拟:
MockitoAnnotations.initMocks(YourTestClass);
Then in your test method you define what execute()
method should return:
然后在您的测试方法中定义execute()
应该返回的方法:
when(defaultHttpClient.execute(any()/* or wahtever you want here */)).thenReturn(stubbed JSON object);
回答by Husyn
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 轻松完成此操作,它也可以轻松模拟最终/静态方法、私有方法和匿名类。这是模拟 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));
回答by user1855042
Here is what I did to test my code using Mockito and Apache HttpBuilder:
这是我使用 Mockito 和 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)
大家怎么看,我需要改进吗?(是的,我知道,评论。那是我从我的 Spock 背景中带来的:D)
回答by Pawe? Adamski
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,我是为内部项目写的,后来决定开源。它允许您使用 fluent API 定义模拟行为,然后验证许多调用。例子:
HttpClientMock httpClientMock = new
HttpClientMock("http://localhost:8080");
httpClientMock.onGet("/login?user=john").doReturnJSON("{permission:1}");
httpClientMock.verify().get("/login?user=john").called();
回答by gnulli
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.
有一种更好的方法可以做到这一点,而无需将 PowerMock 添加为另一个依赖项。在这里你只需要一个额外的构造函数,将 HTTPClient 作为参数和 Mockito。在这个例子中,我正在创建一个自定义健康检查(Spring Actuator),我需要模拟 HTTPClient 进行单元测试。
Libs: JUnit 5, Spring Boot 2.1.2 and Mockito 2.
库:JUnit 5、Spring Boot 2.1.2 和 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)
注意这里我们使用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);
}