使用MockServer测试时如何验证响应数量是否正确?

问题描述 投票:0回答:1

我正在为需要向外部 Web 服务发出 HTTP 请求的 java 服务创建一些单元测试。我决定使用 MockServer (https://www.mock-server.com/#what-is-mockserver) 来模拟外部 HTTP 调用,但到目前为止我似乎无法让它工作。我创建了一个虚拟测试方法只是为了使用 MockServer 进行测试。它设置并启动服务器,添加一些期望,发出简单的 GET 请求,然后验证是否发出了正确数量的请求以及响应是否具有正确的信息。问题是,当我的测试调用 MockServerClient.verify() 时,就会抛出以下异常:

org.mockserver.client.SocketConnectionException: Channel handler removed before valid response has been received
    at org.mockserver.client.HttpClientConnectionErrorHandler.handlerRemoved(HttpClientConnectionErrorHandler.java:20)
    at io.netty.channel.AbstractChannelHandlerContext.callHandlerRemoved(AbstractChannelHandlerContext.java:946)
    at io.netty.channel.DefaultChannelPipeline.callHandlerRemoved0(DefaultChannelPipeline.java:637)
    at io.netty.channel.DefaultChannelPipeline.destroyDown(DefaultChannelPipeline.java:876)
    at io.netty.channel.DefaultChannelPipeline.destroyUp(DefaultChannelPipeline.java:844)
    at io.netty.channel.DefaultChannelPipeline.destroy(DefaultChannelPipeline.java:836)
    at io.netty.channel.DefaultChannelPipeline.access$700(DefaultChannelPipeline.java:46)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelUnregistered(DefaultChannelPipeline.java:1392)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelUnregistered(AbstractChannelHandlerContext.java:198)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelUnregistered(AbstractChannelHandlerContext.java:184)
    at io.netty.channel.DefaultChannelPipeline.fireChannelUnregistered(DefaultChannelPipeline.java:821)
    at io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:827)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at java.lang.Thread.run(Thread.java:745)

过去几天我一直在寻找示例,甚至深入研究源代码以试图理解我做错了什么。我现在已经没有主意了。如果有人可以看看我哪里出错了,或者至少让我指出正确的方向,我将不胜感激。

这是我的单元测试的代码:

@Test
public void getShouldWork() throws URISyntaxException, IOException {
    
    ConfigurationProperties.maxSocketTimeout(200000);       
    
    final String responseBody = "some_response_body";
    final String respHdrName = "some_header";
    final String respHdrVal = "some value";
    
    MockServerClient mockServer = ClientAndServer.startClientAndServer(1080);
    HttpRequest request = HttpRequest.request()
            .withMethod("GET")
            .withPath("/some/url")
            .withQueryStringParameter("id", "9"); 
    mockServer.when(
            request,
            Times.exactly(1)
        )
        .respond(
                HttpResponse.response()
                .withBody(responseBody)
                .withHeader(respHdrName, respHdrVal)
        );

    //The test will throw an exception when executing this line 
    mockServer.verify(request, VerificationTimes.exactly(1));
    
    CloseableHttpClient httpClient = HttpClientBuilder.create()
            .build();
    
    HttpGet getRequest = new HttpGet("http://localhost:" + mockServer.getPort()
            + "/some/url?id=9");
    CloseableHttpResponse resp = httpClient.execute(getRequest);       
    
    try (InputStreamReader isr = new InputStreamReader(resp.getEntity().getContent());
            BufferedReader br = new BufferedReader(isr);) {
        assertThat(br.readLine(), is(responseBody));
        while (br.readLine() != null) {
            // consume content...
        }
    }
    assertThat(resp.getFirstHeader(respHdrName), is(notNullValue()));
    assertThat(resp.getFirstHeader(respHdrName).getValue(), is(respHdrVal));
}
java unit-testing httprequest junit4 mockserver
1个回答
0
投票

出现此问题的原因是 Times.exactly(1) 与当前 MockServer API 冲突。当您指定 Times.exactly(1) 时,MockServer 会强制执行严格的验证,以确保请求仅匹配一次。如果不匹配,则会引发错误。

删除 Times.exactly(1) 默认允许无限制调用 (Times.unlimited()),绕过严格验证并防止错误。

解决方案: 简化:如果精确匹配不重要,请删除 Times.exactly(1)。 更新语法:将 Times.exactly(1) 替换为更符合更新 API 的方法,例如 Times.once()

© www.soinside.com 2019 - 2024. All rights reserved.