如何使用 junit 对 HttpClient 重试逻辑进行单元测试

How to unit test HttpClient retry logic using junit

我正在使用 apache http 客户端来使用服务,我需要根据超时和响应代码重试请求。 为此,我实现了如下代码。如何为超时和响应代码场景的重试逻辑编写 junit 测试。我想以这样的方式编写单元测试,当我发送任何 post/get 请求时,如果它 returns 429 错误代码响应或任何 TimeOutException 我应该确保重试逻辑正确执行。我不知道如何为重试逻辑编写单元测试。 通过谷歌搜索,我找到了下面的 link 但它对我没有帮助。

我正在使用 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;    
   }

谁能帮我解决这个问题。

您的 httpClient 有一个 "target" url,比方说 localhost:1234。您要测试的是您的重试代码,因此您不应该触及 httpClient 本身(因为它不是您的组件,您也不需要测试它。)

所以手头的问题是当你的 localhost:1234 响应有问题时你想看到重试逻辑 运行 (不是你的实现..如果它没有 运行 正确的 conf 是他们的问题)有效..你唯一要做的就是模拟 "localhost:1234" !

此工具 http://wiremock.org/ 是执行此操作的完美选择。您可以为您的目标 url 创建存根,并根据您喜欢的几乎任何内容给出一系列响应。

您的代码应该如下所示 在致电 uploadFile

之前
    stubFor(post(urlEqualTo("/hash"))
        .willReturn(aResponse()
            .withStatus(200)
            .withBody(externalResponse)));

和 在调用 uploadFile

之后

并验证步骤以验证到达模拟端点的模拟请求

    Assert.assert* //... whatever you want to assert in your handlers / code / resposnes
    verify(postRequestedFor(urlEqualTo("/hash")));