Server test support

Spring WS Test provides you a helper class to simplify server side tests.

Code shown here is taken from server test sample application, which can be viewed in SVN repository.

It's possible to download it using following command svn co https://java-crumbs.svn.sourceforge.net/svnroot/java-crumbs/simple-server-test/tags/simple-server-test-0.22/simple-server-test/ simple-server-test

Simple test

If you want to test your server-side Web Service configuration, you can do something like this:

@RunWith(SpringJUnit4ClassRunner.class)
// your endpoint configuration + Default helper config
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring-ws-servlet.xml",
                WsTestHelper.DEFAULT_CONFIG_PATH })
public class EndpointTest {

        @Autowired
        private WsTestHelper helper;

        @Test
        public void testSimple() throws Exception {
                // simulates request coming to MessageDispatcherServlet
                MessageContext message = helper.receiveMessage("request1.xml");
                // assert that response is not fault
                helper.createMessageValidator(message.getResponse()).assertNotSoapFault();
        }
        
        @Test
        public void testCompare() throws Exception {
                // simulates request coming to MessageDispatcherServlet
                MessageContext message = helper.receiveMessage("request1.xml");
                // compare response with control response
                helper.createMessageValidator(message.getResponse()).assertNotSoapFault().compare("response1.xml");
        }
}

This test loads request1.xml and simulates that its content came as a SOAP request. Tested application processes the request and returns a response. The response can be either just validated that it does not contain error or it can be compared with expected value. In the example above the response is compared to response1.xml.

Both request and response can be defined as payload only. If the message does not contain SOAP envelope, the message is automatically wrapped to one.

Please note, that you do not have to start servlet engine. The test can run as normal unit test. Web.xml is ignored, if you have multiple servlets to test, it's possible to write multiple test classes each of them using configuration for given servlet.

Response validation

It's also possible to use more sophisticated validation assertions

        @Test
        public void testAssertXPath() throws Exception {
                // simulates request coming to MessageDispatcherServlet
                MessageContext message = helper.receiveMessage("request1.xml");
                //validate response
                helper.createMessageValidator(message.getResponse()).assertNotSoapFault().validate("xsd/calc.xsd")
                        .addNamespaceMapping("ns", "http://javacrumbs.net/calc").assertXPath("//ns:result=3");
        }

Templates

It is possible to use templates for both request and response. One possible example can look like this.

@Test
public void testResponseTemplate() throws Exception {
        WsTestContextHolder.getTestContext().setAttribute("a", 1);
        WsTestContextHolder.getTestContext().setAttribute("b", 2);
        WsTestContextHolder.getTestContext().setAttribute("result", 3);
        // simulates request coming to MessageDispatcherServlet
        MessageContext message = helper.receiveMessage("request-context-xslt.xml");
        // compare response with control response
        helper.createMessageValidator(message.getResponse()).assertNotSoapFault().compare("response-context-xslt.xml");
        
        WsTestContextHolder.getTestContext().clear();
}

Corresponding template (request-context-xslt.xml):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:param name="a" />
        <xsl:param name="b" />
        <xsl:template match="/">
                <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
                        <soapenv:Header />
                        <soapenv:Body>
                                <plusRequest xmlns="http://javacrumbs.net/calc">
                                        <a><xsl:value-of select="$a" /></a>
                                        <b><xsl:value-of select="$b" /></b>
                                </plusRequest>
                        </soapenv:Body>
                </soapenv:Envelope>
        </xsl:template>
</xsl:stylesheet>

Alternative configuration

It is possible to change the default WsTestHelper configuration. It's just necessary to write standard Spring configuration file and use it instead of WsTestHelper.DEFAULT_CONFIG_PATH. Here is an example of using FreeMarker templating engine.

@RunWith(SpringJUnit4ClassRunner.class)
// your endpoint configuration + alternative helper config
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring-ws-servlet.xml",
                "classpath:spring/alternative-helper-config.xml" })
public class AlternativeEndpointTest {

        @Autowired
        private WsTestHelper helper;

        @Test
        public void testSimple() throws Exception {
                // simulates request coming to MessageDispatcherServlet
                MessageContext message = helper.receiveMessage("request1.xml");
                // compare response with control response
                helper.createMessageValidator(message.getResponse()).compare("response1.xml");
        }
}

The corresponding configuration file (alternative-helper-config.xml) looks like this.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

        <bean class="net.javacrumbs.springws.test.helper.DefaultWsTestHelper">
                <property name="templateProcessor">
                        <bean class="net.javacrumbs.springws.test.template.FreeMarkerTemplateProcessor"/>
                </property>
        </bean>

</beans>

WebServiceTemplate test

It's not necessary to use WsTestHelper for the test. It's also possible to use WebServiceTemplate. In order to do this, you have to configure it

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

        <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                <property name="contextPath" value="net.javacrumbs.calc.model" />
        </bean>

        <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
                <property name="marshaller" ref="marshaller"/>
                <property name="unmarshaller" ref="marshaller"/>
                <property name="defaultUri" value="http://localhost"/>
                <property name="messageSender">
                        <bean class="net.javacrumbs.springws.test.helper.InMemoryWebServiceMessageSender"/>
                </property>
        </bean>
        
</beans>

Then, you can write test as normal Spring WS client. For example:

@RunWith(SpringJUnit4ClassRunner.class)
// your endpoint configuration + extended config
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring-ws-servlet.xml",
                "classpath:spring/marshalling-helper-config.xml" })
public class MarshallingEndpointTest {

        @Autowired
        private WebServiceOperations wsTemplate;
        
        @Test
        public void testSimple() throws Exception {
                PlusRequest request = new PlusRequest();
                request.setA(1);
                request.setB(2);
                
                PlusResponse response = (PlusResponse) wsTemplate.marshalSendAndReceive(request);
                // assert that response is not fault
                assertEquals(3, response.getResult());
        }
        @Test
        public void testError() throws Exception {
                PlusRequest request = new PlusRequest();
                request.setA(Integer.MAX_VALUE);
                request.setB(2);
                
                try
                {
                        wsTemplate.marshalSendAndReceive(request);
                        fail("Exception expected");
                }
                catch(SoapFaultClientException e)
                {
                        assertEquals("Values are too big.",e.getSoapFault().getFaultStringOrReason());
                        //or an alternative error validation 
                        new MessageValidator(e.getWebServiceMessage()).assertSoapFault().assertFaultStringOrReason("Values are too big.");
                }

        }
}