Java 如何使用junit对HttpClient重试逻辑进行单元测试
我正在使用ApacheHTTP客户端来使用服务,我需要根据超时和响应代码重试请求。 为此,我实现了如下代码。如何为超时和响应代码场景的重试逻辑编写junit测试。我希望以这样的方式编写单元测试:当我发送任何post/get请求时,如果它返回429错误代码响应或任何TimeOutException,我应该确保正确执行重试逻辑。我不知道如何为重试逻辑编写单元测试。 通过谷歌搜索,我找到了下面的链接,但它对我没有帮助 我正在使用junit、Mockito编写单元测试,并使用PowerMock来模拟静态方法Java 如何使用junit对HttpClient重试逻辑进行单元测试,java,junit,mockito,apache-httpclient-4.x,powermock,Java,Junit,Mockito,Apache Httpclient 4.x,Powermock,我正在使用ApacheHTTP客户端来使用服务,我需要根据超时和响应代码重试请求。 为此,我实现了如下代码。如何为超时和响应代码场景的重试逻辑编写junit测试。我希望以这样的方式编写单元测试:当我发送任何post/get请求时,如果它返回429错误代码响应或任何TimeOutException,我应该确保正确执行重试逻辑。我不知道如何为重试逻辑编写单元测试。 通过谷歌搜索,我找到了下面的链接,但它对我没有帮助 我正在使用junit、Mockito编写单元测试,并使用PowerMock来模拟静
public class GetClient {
private static CloseableHttpClient httpclient;
public static CloseableHttpClient getInstance() {
try {
HttpClientBuilder builder = HttpClients.custom().setMaxConnTotal(3)
.setMaxConnPerRoute(3);
builder.setRetryHandler(retryHandler());
builder.setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy() {
int waitPeriod = 200;
@Override
public boolean retryRequest(final HttpResponse response, final int executionCount,
final HttpContext context) {
int statusCode = response.getStatusLine().getStatusCode();
return (((statusCode == 429) || (statusCode >= 300 && statusCode <= 399))
&& (executionCount < 3));
}
@Override
public long getRetryInterval() {
return waitPeriod;
}
});
httpclient = builder.build();
} catch (Exception e) {
//handle exception
}
return httpclient;
}
private static HttpRequestRetryHandler retryHandler() {
return (exception, executionCount, context) -> {
if (executionCount > maxRetries) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof InterruptedIOException) {
// Timeout
return true;
}
if (exception instanceof UnknownHostException) {
// Unknown host
return false;
}
if (exception instanceof ConnectTimeoutException) {
// Connection refused
return false;
}
if (exception instanceof SSLException) {
// SSL handshake exception
return false;
}
HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// Retry if the request is considered idempotent
return true;
}
return false;
};
}
}
public CloseableHttpResponse uploadFile(){
CloseableHttpClient httpClient = GetClient.getInstance();
CloseableHttpResponse response = null;
try {
response = httpClient.execute(post);
} catch (Exception ex) {
//handle exception
}
return response;
}
public类GetClient{
私有静态可关闭httpclient httpclient;
公共静态CloseableHttpClient getInstance(){
试一试{
HttpClientBuilder builder=HttpClients.custom().SetMaxConntTotal(3)
.setMaxConnPerRoute(3);
setRetryHandler(retryHandler());
builder.setServiceUnavailableRetryStrategy(新ServiceUnavailableRetryStrategy(){
int waitPeriod=200;
@凌驾
公共布尔retryRequest(最终HttpResponse响应,最终int executionCount,
最终HttpContext(上下文){
int statusCode=response.getStatusLine().getStatusCode();
返回((statusCode==429)| |(statusCode>=300&&statusCode){
如果(executionCount>maxRetries){
//如果超过最大重试次数,请不要重试
返回false;
}
if(InterruptedIOException的异常实例){
//超时
返回true;
}
if(未知后异常的异常实例){
//未知宿主
返回false;
}
if(ConnectTimeoutException的异常实例){
//拒绝连接
返回false;
}
if(SSLexException的异常实例){
//SSL握手异常
返回false;
}
HttpClientContext=HttpClientContext.adapt(上下文);
HttpRequest请求=clientContext.getRequest();
布尔幂等元=!(HttpEntityEnclosingRequest的请求实例);
if(幂等){
//如果请求被认为是幂等的,请重试
返回true;
}
返回false;
};
}
}
public CloseableHttpResponse uploadFile(){
CloseableHttpClient httpClient=GetClient.getInstance();
CloseableHttpResponse响应=null;
试一试{
response=httpClient.execute(post);
}捕获(例外情况除外){
//处理异常
}
返回响应;
}
有人能帮我一下吗。您的httpClient有一个“目标”url,比如localhost:1234。您要测试的是重试代码,所以您不应该触碰httpClient本身(因为它不是您的组件,您不应该也测试它)
因此,当前的问题是当您的localhost:1234响应出现问题时,您希望看到将运行的重试逻辑(而不是您的实现..如果它没有使用正确的配置运行,那么这就是问题所在..您唯一需要做的就是模拟“localhost:1234”
此工具是实现此目的的最佳选择。您可以为目标url创建存根,并根据您喜欢的任何内容给出一系列响应
您的代码应该如下所示
调用uploadFile
stubFor(post(urlEqualTo(“/hash”))
.willReturn(aResponse()
.withStatus(200)
.与身体(外部反应));
及
调用uploadFile
和验证步骤,以验证到达模拟端点的模拟请求
Assert.Assert*/…您想在处理程序/code/resposnes中断言的任何内容
验证(postRequestedFor(urlEqualTo(“/hash”));
你是如何为这个类编写单元测试的?你有没有成功调用uploadFile
的测试?我还想看看uploadFile()
的一个简单运行测试。首先,这里的结构经常调用静态项,不利于编写单元测试,而PowerMock不是我的朋友(除了白盒)。我的总体策略是将httpclient构建为一个模拟,为适当的方法抛出一个异常(例如,使用Mockito.when(…)。然后抛出(…)。然后返回(…)
),并让模拟使用Mockito.doCallRealMethod()
了解正确的方法。但总而言之,没有看到上传文件
方法的工作版本这只是一个猜测。本指南是我在wiremock上的最爱之一。看一看,让我知道你是否同意。对于多个响应,只需在存根上重复将返回
方法。它将在同一个wa中工作y作为junit。每次调用存根时,它都会提供下一行willReturn。wiremock服务器将运行在类似localhost:9999的环境中。这在urlEqualsTo()中被省略,需要提供给代码一些配置(因为url不应该硬编码,应该已经实现以注入配置)尾随url/fetch/token可能是硬编码的,因为它是项目的核心路径,可以按原样使用。因此urlEqualsTo(“/fetch/token”)。您应该在测试中使用绝对路径,并定义所有内容以减少无意义/错误的测试。因此,请使用urlEqualsTo(“/fetch/token”)启动wiremock.stub添加2-3将返回运行您的测试,然后进行验证!JaCoCo不应该关心您的测试框架(wiremock等),因为它会增强您创建覆盖率的实际代码。我没有使用