Webserviceioexception When Testing a Web Service Client Using Mockwebserviceserver
I'm Trying to Write an Integration Test and Part of That Test Requires Mocking a Rest Call and Also a Soap Call. the Rest Part Works Fine, I'm Able to Mock...
I'm trying to write an integration test and part of that test requires mocking a REST call and also a SOAP call. The REST part works fine, I'm able to mock that. The SOAP call is proving difficult to mock. I get an WebServiceIOException.
Caused by: org.springframework.ws.client.WebServiceIOException: I/O error: Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:561)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)
at ca.nbc.payment.pmt_commons_mcp_connector.service.OdsPreferencesConnector.getPreferences(OdsPreferencesConnector.java:18)
at ca.nbc.payment.pmt_commons_mcp_connector.service.McpConnectorMessageService.processGetCustomerMessage(McpConnectorMessageService.java:46)
at ca.nbc.payment.pmt_commons_mcp_connector.stream.McpConnectorStreamListener.handleCustomerManagementMessageRetrieve(McpConnectorStreamListener.java:29)
at (Native Method)
at (NativeMethodAccessorImpl.java:62)
at (DelegatingMethodAccessorImpl.java:43)
at (Method.java:566)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
at org.springframework.cloud.stream.binding.StreamListenerMessageHandler.handleRequestMessage(StreamListenerMessageHandler.java:55)
Here is my client class, the class that extends WebServiceGatewaySupport
public class OdsPreferencesConnector extends WebServiceGatewaySupport {
@Value("${ods.url}")
private String odsUrl;
public String getPreferences(String memberIdNo) {
GetPreferencesResponse getPreferencesResponse = (GetPreferencesResponse) getTemplate().marshalSendAndReceive(odsUrl, getGetPreferencesRequest(memberIdNo));
if (!getPreferencesResponse.getServiceResponse().getPreferenceList().getPreference().isEmpty()) {
return getPreferencesResponse.getServiceResponse().getPreferenceList().getPreference().get(0).getPrefValue();
}
return null;
}
private WebServiceTemplate getTemplate() {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setClassesToBeBound(GetPreferencesRequest.class, GetPreferencesResponse.class);
webServiceTemplate.setMarshaller(jaxb2Marshaller);
webServiceTemplate.setUnmarshaller(jaxb2Marshaller);
return webServiceTemplate;
}
private GetPreferencesRequest getGetPreferencesRequest(String memberIdNo) {
GetPreferencesRequest getPreferencesRequest = new GetPreferencesRequest();
getPreferencesRequest.setServiceRequest(new GetPreferencesRequestType());
getPreferencesRequest.getServiceRequest().setPartyNumber(new PartyNumberType());
getPreferencesRequest.getServiceRequest().getPartyNumber().setMemberIdNo(memberIdNo);
return getPreferencesRequest;
}
}
Here is my test class
@SpringBootTest
@ActiveProfiles("integration-tests")
class IntegrationTest {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private MessageCollector messageCollector;
@Autowired
private McpConnectorStream mcpConnectorStream;
@Autowired
private static OdsPreferencesConnector odsPreferencesConnector;
private static MockWebServiceServer mockServer;
private static WireMockServer wireMockServer;
@BeforeAll
public static void setup() {
wireMockServer = new WireMockServer(options().bindAddress("127.0.0.1").port(14000));
wireMockServer.start();
odsPreferencesConnector = new OdsPreferencesConnector();
ReflectionTestUtils.setField(odsPreferencesConnector, "odsUrl", "");
mockServer = MockWebServiceServer.createServer(odsPreferencesConnector);
}
@AfterAll
public static void afterAll() {
wireMockServer.stop();
}
@Test
void handleCustomerManagementMessageGet() throws Exception {
PaymentCommonsCustomer receivedMessage = TestObjectBuilder.createPaymentCommonsCustomerMessage();
GetIndividualBaseResponse getIndividualBaseResponse = TestObjectBuilder.createIndividualBaseResponse();
// Mock MCP REST call
wireMockServer.stubFor(WireMock.get("/individuals/" + receivedMessage.getBncId() + "/base")
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withBody(objectMapper.writeValueAsString(getIndividualBaseResponse))));
// Mock ODS SOAP call
Source requestPayload = new StringSource(TestObjectBuilder.createGetPreferencesRequestXML());
Source responsePayload = new StringSource(TestObjectBuilder.createGetPreferencesResponseXML());
mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));
sendMessage(receivedMessage, StreamAction.ACTION_GET);
Message<String> sentMessageJson = (Message<String>) messageCollector.forChannel(mcpConnectorStream.outboundCustomerApi()).poll();
assertNotNull(sentMessageJson);
PaymentCommonsCustomer sentMessage = objectMapper.readValue(sentMessageJson.getPayload(), PaymentCommonsCustomer.class);
assertEquals(receivedMessage.getMessageId(), sentMessage.getMessageId());
assertEquals(receivedMessage.getTransactionDate(), sentMessage.getTransactionDate());
assertEquals(receivedMessage.getLastPublishedDate(), sentMessage.getLastPublishedDate());
}
private void sendMessage(PaymentCommonsCustomer message, String action) throws Exception {
mcpConnectorStream.inboundMcpConnector().send(MessageBuilder.withPayload(objectMapper.writeValueAsString(message)).setHeader("action", action).build());
}
}
If the SOAP web service is up, then my unit test works fine. Is there something I'm missing or doing wrong? I'm using Java 11 and JUnit 5.
1 Answer
I had a similar issue recently. The problem is your WebServiceTemplate, you are creating a new instance each time you call your service.
Instead of that, try to either inject a WebServiceTemplate or use the one WebServiceGatewaySupport.getWebServiceTemplate() provides by default and do not manipulate anything from the service template when you call your service.
One thing that MockWebServiceServer.createServer(client) does, it's to take your service template and set a MockWebServiceMessageSender as a message sender which is the one you need to avoid the actual http call, in your code the mock is never been called because the creation of a new service template instance everytime. Finally, you won't need the WireMockServer