我正在为需要向外部 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));
}
出现此问题的原因是 Times.exactly(1) 与当前 MockServer API 冲突。当您指定 Times.exactly(1) 时,MockServer 会强制执行严格的验证,以确保请求仅匹配一次。如果不匹配,则会引发错误。
删除 Times.exactly(1) 默认允许无限制调用 (Times.unlimited()),绕过严格验证并防止错误。
解决方案: 简化:如果精确匹配不重要,请删除 Times.exactly(1)。 更新语法:将 Times.exactly(1) 替换为更符合更新 API 的方法,例如 Times.once()