简体   繁体   中英

MockRestServiceServer returns 404 status instead of mocking external service response

I'm writing an outbound HttpRequestExecutingMessageHandler based service activator which sends a POST request to the 3rd party REST API and gets a JSON in response. The 3rd party REST API accepts JSON object as payload. The relevant test methods are as follows:

  @BeforeEach
  public void setUp() {
    server = MockRestServiceServer.createServer(restTemplateBuilder.additionalMessageConverters(
                httpMessageConverter).build());
    messagingTemplate = new MessagingTemplate();
    defaultDestination = new QueueChannel(1);
  }

and

  @Test
  void testOutboutSMSRequestHanlder() throws Exception {

    SMSTaskRequest request = new SMSTaskRequest("1", 
                               Arrays.asList(new SMSTask(1, "123456", "Test Message")));

    SMSTaskResponse response = new SMSTaskResponse("200", "OK", "task-status", 
                                 Arrays.asList(new SMSTaskStatus("1", "0 OK")));

    server.expect(requestTo("http://localhost/foo/bar"))
       .andRespond(withSuccess(objectMapper.writeValueAsString(response), APPLICATION_JSON));

    messagingTemplate.send(outboundSMSRequestChannel, 
         MessageBuilder.withPayload(request)
        .setHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE).setReplyChannel(defaultDestination).build());

    SMSTaskResponse smsTaskResponse = messagingTemplate
        .receiveAndConvert(defaultDestination, SMSTaskResponse.class);

    assertThat(smsTaskResponse).isEqualTo(response);
  }

I get a 404 error for the external service request even after configuring my gateway as follows

@Component
public class OutboundSMSHandlerGateway {

  @Autowired
  private MappingJackson2HttpMessageConverter httpMessageConverter;

  @Bean
  public PublishSubscribeChannel outboundSMSRequestChannel() {
    return new PublishSubscribeChannel();
  }

  @ServiceActivator(inputChannel = "outboundSMSRequestChannel")
  @Bean
  public HttpRequestExecutingMessageHandler handleGatewaySMSRequest() {
    HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://localhost/foo/bar");
    handler.setHttpMethod(POST);
    handler.setExpectReply(true);
    handler.setMessageConverters(Arrays.asList(httpMessageConverter));
    handler.setExpectedResponseType(SMSTaskResponse.class);
    return handler;
  }
}

The error stack trace is as follows

org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [http://localhost/foo/bar] in the [bean 'handleGatewaySMSRequest'; defined in: 'class path resource [com/thoughtscape/sms/OutboundSMSHandlerGateway.class]'; from source: 'org.springframework.core.type.classreading.SimpleMethodMetadata@19f9d595']; nested exception is org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found: [<html>
    <head>
        <title>Valet - Not Found</title>

        <style>
            body {
                font-family: monospace;
            }
        </style>
    </head>
    <body>
        404 - Not Found
    </body>
</html>
]
, failedMessage=GenericMessage [payload=SMSTaskRequest(type=send-sms, taskNum=1, smsTasks=[SMSTask(taskID=1, recipient=123456, messageContent=Test Message, flashSms=null, characterCodingSet=null, smsCodec=null, successReport=null, failureReport=null, enableSmsReport=null)]), headers={replyChannel=org.springframework.integration.channel.QueueChannel@38f502fc, id=43ed8efa-7aea-34bd-6884-1938ed65e9d3, Content-Type=application/json, timestamp=1602675489316}]
    at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.exchange(HttpRequestExecutingMessageHandler.java:210)
    at org.springframework.integration.http.outbound.AbstractHttpRequestExecutingMessageHandler.handleRequestMessage(AbstractHttpRequestExecutingMessageHandler.java:320)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:62)
    at org.springframework.integration.dispatcher.BroadcastingDispatcher.invokeHandler(BroadcastingDispatcher.java:224)
    at org.springframework.integration.dispatcher.BroadcastingDispatcher.dispatch(BroadcastingDispatcher.java:180)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:570)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:520)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:187)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:166)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:47)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:109)
    at com.thoughtscape.sms.SmsServiceApplicationTests.testOutboutSMSRequestHanlder(SmsServiceApplicationTests.java:87)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found: [<html>
    <head>
        <title>Valet - Not Found</title>

        <style>
            body {
                font-family: monospace;
            }
        </style>
    </head>
    <body>
        404 - Not Found
    </body>
</html>
]
    at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:113)
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:184)
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:125)
    at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:782)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:740)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:695)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:593)
    at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.exchange(HttpRequestExecutingMessageHandler.java:196)
    ... 76 more

MockRestServiceServer returns 404 status instead of mocking external service response

Don't confuse yourself: there is full no interaction with your mock server at all. You just perform a real HTTP call.

Let's analyze your code!

server = MockRestServiceServer.createServer(restTemplateBuilder.additionalMessageConverters(
            httpMessageConverter).build());

So, you try to mock some result of restTemplateBuilder and you are done here: no any reference to the server neither to the RestTemplate !

I get a 404 error for the external service request even after configuring my gateway as follows

HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://localhost/foo/bar");
handler.setHttpMethod(POST);
handler.setExpectReply(true);
handler.setMessageConverters(Arrays.asList(httpMessageConverter));
handler.setExpectedResponseType(SMSTaskResponse.class);
return handler;

And what? Where is an interaction with the mock server? See docs on the matter: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/testing.html#spring-mvc-test-client

The very important phrase:

// Test code that uses the above RestTemplate ...

So, what you need to make it working properly is a RestTemplate bean injected into that HttpRequestExecutingMessageHandler . And the same RestTemplate instance must be used from that MockRestServiceServer.createServer() . Only this way your HTTP outbound gateway is going to interact with the mocked RestTemplate which is going to pull answers from the mentioned mock server.

Otherwise the HttpRequestExecutingMessageHandler creates its own internal RestTemplate which knows nothing about mocking and is going to perform real request to the mentioned URL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM