Spring WS Server Side Integration Testing
This tutorial shows how to create integration tests for your spring ws soap endpoints using JUnit. Spring WS has a great framework for writing clean and powerful integration tests. By using the MockWebServiceClient
we can make requests to our soap services. We can create requests using RequestCreators
and verify the responses using ResponseMatchers
. This also allows us to validate the request/response with an XSD Schema and to validate the response for known exceptional cases.
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-test</artifactId>
<version>2.2.4.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
<scope>test</scope>
</dependency>
We are going to test the following service. We made a very basic service that accepts a GetBeerRequest
and evaluates the id. If the id == 0 then an exception will be thrown. Finally we return a GetBeerResponse
.
package com.memorynotfound.server;
import com.memorynotfound.beer.*;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
@Endpoint
public class BeerEndpoint {
public static final String NAMESPACE_URI = "https://memorynotfound.com/beer";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getBeerRequest")
@ResponsePayload
public GetBeerResponse getBeer(@RequestPayload GetBeerRequest request) {
if (request.getId() == 0){
throw new RuntimeException("id cannot be 0");
}
// empty response
return new GetBeerResponse();
}
}
We configure our endpoint using the following spring java configuration.
package com.memorynotfound.server;
import com.memorynotfound.server.BeerEndpoint;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver;
import org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver;
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
@EnableWs
@Configuration
@ComponentScan
public class SoapServerConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext appContext){
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(appContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name = "beers")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema schema){
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("BeersPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace(BeerEndpoint.NAMESPACE_URI);
wsdl11Definition.setSchema(schema);
return wsdl11Definition;
}
@Bean
public XsdSchema beersSchema(){
return new SimpleXsdSchema(new ClassPathResource("xsd/beers.xsd"));
}
}
Spring WS provides an easy framework for writing clean integration tests for your soap endpoints. We start by adding the SpringJUnit4ClassRunner
with the @RunWith
annotation. Then we annotate the class using the @ContextConfiguration
annotation and add our configuration file we created earlier. Now the class is able to inject spring dependencies, we can create a MockWebServiceClient
. This client lets us make requests to our created soap endpoints. We can create requests using RequestCreators
and verify the responses using ResponseMatchers
. This also allows us to validate the request/response with an XSD Schema and to validate the response for known exceptional cases.
package com.memorynotfound.spring.ws;
import com.memorynotfound.server.SoapServerConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ws.test.server.MockWebServiceClient;
import org.springframework.xml.transform.StringSource;
import javax.xml.transform.Source;
import java.io.IOException;
import static org.springframework.ws.test.server.RequestCreators.withPayload;
import static org.springframework.ws.test.server.ResponseMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SoapServerConfig.class)
public class BeerEndpointIntegrationTest {
@Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
private Resource xsdSchema = new ClassPathResource("xsd/beers.xsd");
@Before
public void init(){
mockClient = MockWebServiceClient.createClient(applicationContext);
}
@Test
public void valid_xsd_request_response_test() throws IOException {
Source requestPayload = new StringSource(
"<ns2:getBeerRequest xmlns:ns2=\"https://memorynotfound.com/beer\">" +
"<ns2:id>1</ns2:id>" +
"</ns2:getBeerRequest>");
Source responsePayload = new StringSource(
"<ns2:getBeerResponse xmlns:ns2=\"https://memorynotfound.com/beer\"></ns2:getBeerResponse>");
mockClient
.sendRequest(withPayload(requestPayload))
.andExpect(noFault())
.andExpect(payload(responsePayload))
.andExpect(validPayload(xsdSchema));
}
@Test
public void id_cannot_be_0_test() throws IOException {
Source requestPayload = new StringSource(
"<ns2:getBeerRequest xmlns:ns2=\"https://memorynotfound.com/beer\">" +
"<ns2:id>0</ns2:id>" +
"</ns2:getBeerRequest>");
mockClient
.sendRequest(withPayload(requestPayload))
.andExpect(serverOrReceiverFault());
}
}
I have tried this code and it returns the following error:
“An Authentication object was not found in the SecurityContext”.
When I make this request with curl everything works.