我正在开发一个api来通过HTTP发出批量请求。由此建议(How to make batch http call in java),我决定使用多线程。
这是实施:
public class GetItems {
//Control the number of connections made to the server.
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(120);
cm.setDefaultMaxPerRoute(30);
HttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
//Using concurrent map to store the result from different threads
private Map<String, ItemAttributesFromDatapath> itemDataMap = Maps.newConcurrentMap();
//requests' batch
private List<Request> requests;
public List<String> call() {
List<Thread> threads = Lists.newArrayList();
requests.forEach(request -> {
Thread thread = new Thread(new GetTask(client, request));
thread.start();
threads.add(thread);
});
threads.forEach(thread -> {
try {
thread.join();
} catch (Exception ex) {
LOGGER.error(ex);
}
});
}
//Inner class for multi-thread.
public class GetTask implements Runnable{
private CatalogHttpRequest request;
private CatalogHttpClient client;
private String asin;
public GetTask(HttpClient client, final HttpRequest request) {
this.request = request;
this.client = client;
}
@Override
public void run(){
try{
HttpResponse response = client.executeHttpRequest(request);
try {
if (response.isOK()) {
//some logic here
String item = handle(response)
itemDataMap.put(itemId, item);
} else {
String message = "Is Client Error";
LOGGER.error(message);
}
} catch (Exception ex){
LOGGER.error(ex.getMessage());
}
} catch (Exception ex) {
LOGGER.error(ex.getMessage());
}
}
}
}
然后我尝试编写单元测试,
@Test
public void testBatchRequest() throws Exception{
HttpClient = mockClient(...);
GetItems batch = new GetItems(...);
List<String> ret = batch.call();}
在mockClient方法中,我使用Mockito模拟了一些类:
private HttpClient mockSuccessfulClient(InputStream responseStream, int code) throws IOException{
HttpEntity entity = Mockito.mock(HttpEntity.class);
when(entity.getContent()).thenReturn(responseStream);
HttpResponse response = Mockito.mock(CloseableHttpResponse.class);
when(response.getEntity()).thenReturn(entity);
StatusLine statusLine = Mockito.mock(StatusLine.class);
when(statusLine.getStatusCode()).thenReturn(code);
when(response.getStatusLine()).thenReturn(statusLine);
//CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class);
//when(httpClient.execute(any())).thenReturn(response);
CatalogHttpClient client = Mockito.mock(HttpClient.class);
when(client.executeHttpRequest(any())).thenReturn(response);
return client;
}
现在对于单元测试,返回列表为空,这是不正确的。
我尝试通过设置断点来调试代码,发现主要代码在线程启动时没有在GetTask中执行run()方法。
因为我不熟悉多线程的东西。这个问题对你来说可能显得愚蠢,但是你可以帮我弄清楚代码中的错误以及如何为我的案例编写正确的测试。
另外,我不确定ConcurrentMap是否是将结果存储在多个线程中的好习惯?