我正在尝试为 http post 实现编写一个单元测试。但是我无法正确模拟 httpclient,并且我的 when 语句永远不会被触发。我编写的单元测试是进行实际的 http 调用,而不是使用模拟响应进行响应。 我们如何继续模拟由 HttpClientBuilder 创建的客户端?
Http 方法实现:
HttpResponse postRequest(String url, String request) {
HttpResponse resp = null;
try {
HttpClient client = HttpClientBuilder.create().useSystemProperties().build();
HttpPost post = new HttpPost(url);
post.addHeader("Content-Type", "application/x-www-form-urlencoded");
post.setEntity(new StringEntity(request));
resp = client.execute(post);
} catch (Exception e) {
return null;
}
}
测试方法:
@Mock
private HttpClient httpClient;
when(httpClient.execute(any())).thenReturn(httpResponse);
我们如何继续模拟由 HttpClientBuilder 创建的客户端?
我们没有!!
尽量避免嘲笑第三方的担忧
创建紧密耦合静态实现关注点的抽象
public interface HttpClientFactory {
public HttpClient create();
}
通过将在生产中使用的简单实现。
public class HttpClientFactoryImpl implements HttpClientFactory {
//...
public HttpClient create() {
return HttpClientBuilder.create().useSystemProperties().build();
}
//...
}
使用依赖关系反转,封装类应显式依赖于抽象,以避免违反单一责任原则 (SRP(
public class SystemUnderTest {
private HttpClientFactory httpClientFactory;
public SystemUnderTest(HttpClientFactory httpClientFactory) {
this.httpClientFactory = httpClientFactory;
}
HttpResponse postRequest(String url, String request) {
HttpResponse resp = null;
try {
HttpClient client = httpClientFactory.create();
HttpPost post = new HttpPost(url);
post.addHeader("Content-Type", "application/x-www-form-urlencoded");
post.setEntity(new StringEntity(request));
resp = client.execute(post);
return resp;
} catch (Exception e) {
return null;
}
}
}
这种关注点分离 (SoC( 允许它(封装类(更灵活地进行隔离单元测试。
@Test
public void testPostRequest() throws Exception {
// Arrange
HttpResponse expected = mock(HttpResponse.class);
HttpClient httpClient = mock(HttpClient.class);
when(httpClient.execute(any())).thenReturn(expected);
HttpClientFactory httpClientFactory = mock(HttpClientFactory.class);
when(httpClientFactory.create()).thenReturn(httpClient);
SystemUnderTest systemUnderTest = new SystemUnderTest(httpClientFactory);
String url = "http://url_here";
String request = "Hello World";
// Act
HttpResponse actual = systemUnderTest.postRequest(url, request);
// Assert
assertEquals(expected, actual);
//should also verify that the expected arguments as passed to execute()
}