Enterprise Integration Zone is brought to you in partnership with:

Enterprise Architect in HCL Technologies a $7Billion IT services organization. My role is to work as a Technology Partner for large enterprise customers providing them low cost opensource solutions around Java, Spring and vFabric stack. I am also working on various projects involving, Cloud base solution, Mobile application and Business Analytics around Spring and vFabric space. Over 23 yrs, I have build repository of technologies and tools I liked and used extensively in my day to day work. In this blog, I am putting all these best practices and tools so that it will help the people who visit my website. Krishna is a DZone MVB and is not an employee of DZone and has posted 64 posts at DZone. You can read more from them at their website. View Full User Profile

JUnit testing with Spring Integration and Spring WS

02.15.2013
| 7496 views |
  • submit to reddit
Spring Integration, Spring WS for Webservice is a decent framework to design and implement a Webservice. It also has good JUnit testing support. In this section I will be talking about how we implement a Webservice using Test Driven Development (TDD). The working sample is here in Github.

As a first step we need to define the XSD schema:

<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:data="http://mycompany.com/it/enterprise/data/v1" xmlns:msg="http://mycompany.com/it/enterprise/msg/v1" xmlns:svc="http://mycompany.com/it/enterprise/contract/TestService/v1" targetNamespace="http://mycompany.com/it/enterprise/contract/TestService/v1" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0">  <xsd:import namespace="http : //mycompany.com/it/enterprise/data/v1" schemaLocation="TestTransactions_v1.xsd"/>
<xsd:element name="TestServiceRequest" type="data:TestServiceRequestType"/>
<xsd:element name="TestServiceResponse" type="data:TestServiceResponseType"/>
</xsd:schema>

<?xml version="1.0" encoding="UTF-8"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:data="http://mycompany.com/it/enterprise/data/v1" xmlns:msg="http://mycompany.com/it/enterprise/msg/v1" targetNamespace="http://mycompany.com/it/enterprise/data/v1" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:complexType name="TestServiceRequestType">
<xsd:sequence>
<xsd:element name="Document">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Id" type="xsd:string" minOccurs="0"/>
<xsd:element name="Type" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TestServiceResponseType">
<xsd:sequence>
<xsd:element name="Document">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Result" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Writing the JUnit test as below,

public class TestIntegrationEndPointTest {

@Autowired
private ApplicationContext applicationContext;

private MockWebServiceClient mockClient;

@Before
public void createClient() {
mockClient = MockWebServiceClient.createClient(applicationContext);
}

@Test
public void testWsEndPointTest() throws Exception {
Source requestPayload = new StringSource("<?xml version=\"1.0\" encoding=\"UTF-8\"?><v1:TestServiceRequest xmlns:v1=\"http://mycompany.com/it/enterprise/contract/TestService/v1\" xmlns:v11=\"http://mycompany.com/it/enterprise/data/v1\"><v11:Document><v11:Id>101</v11:Id><v11:Type>MaterialMaster</v11:Type></v11:Document></v1:TestServiceRequest>");
Source responsePayload = new StringSource("<testServiceResponseType xmlns=\"http://mycompany.com/it/enterprise/data/v1\" xmlns:ns2=\"http://mycompany.com/it/enterprise/contract/TestService/v1\"><Document><Result>SUCCESS</Result></Document></testServiceResponseType>");

mockClient.sendRequest(withPayload(requestPayload)).andExpect(payload(responsePayload));
}
}

Now the test will still fail with need for Spring autowiring, the spring bean definition configuration for Spring WS looks as below,

<bean>
<property name="endpointMap">
<map>
<entry key="{http://mycompany.com/it/enterprise/contract/TestService/v1}TestServiceRequest" value-ref="TestBatchEndpoint" />
</map>
</property>
</bean>
<int-ws:inbound-gateway id="TestBatchEndpoint" reply-channel="test.batch.webservice.out" request-channel="test.batch.webservice.in" />
<bean id="marshaller" >
<property name="contextPath" value="com.mycompany.it.enterprise.contract.testservice.v1" />
</bean>
<bean id="testServiceActivator" class="com.mycompany.it.eis.webservice.ws.TestServiceActivator"/>
<bean id="resultTransformer" class="org.springframework.integration.xml.transformer.ResultToStringTransformer"/>

Spring Integration and Spring WS flow looks as below

<int:bridge  input-channel="test.batch.webservice.in" output-channel="test.batch.webservice.unmarshalling.in"></int:bridge>
<int-xml:unmarshalling-transformer id="defaultUnmarshaller" input-channel="test.batch.webservice.unmarshalling.in" output-channel="test.batch.webservice.unmarshalling.out" unmarshaller="marshaller"/>
<int:service-activator id="test.batch.webservice.activator" input-channel="test.batch.webservice.unmarshalling.out" ref="testServiceActivator" output-channel="test.batch.webservice.marshalling.in">
</int:service-activator>
<int-xml:marshalling-transformer input-channel="test.batch.webservice.marshalling.in" output-channel="test.batch.webservice.out" marshaller="marshaller" result-transformer="resultTransformer" />

IBatisTemplate looks as below,

<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">>
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>

You need to create the Java stubs from the XSL for that you need to run,

mvn jaxb2:xjc

It assumes that you have XSDs at location src/main/xsd location by default, refer this article for more details.

In the Test class, you need to add the Spring JUnit testing capabilities as follows,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
"classpath:META-INF/spring/test-webservice/test-webservice-integration-config.xml",
"classpath:config/test-webservice-beans-config-test.xml" })
public class TestIntegrationEndPointTest {

TestServiceActivator looks somewhat as below:

public class TestServiceActivator {
private static Logger logger = Logger.getLogger(TestServiceActivator.class);

@Autowired
SqlMapClientTemplate ibatisTemplate;

public TestServiceResponseType processRequest(JAXBElement element)    throws Exception {
TestServiceRequestType request = (TestServiceRequestType) element.getValue();
String status = "SUCCESS";
String type = request.getDocument().getType();
String id = request.getDocument().getId();

TestObject notifyObject = new TestObject();
notifyObject.setId(id);
notifyObject.setType(type);
ibatisTemplate.insert("testInsert", notifyObject);

TestServiceResponseType response = new TestServiceResponseType();

Document doc = new Document();
doc.setResult(status);
response.setDocument(doc);

logger.debug("Successfully saved request");

return response;
}
}

One hack we need to do is, we need to add @XmlRootElement to the stubs that were created as per this article

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TestServiceResponseType", propOrder = {
"document"
})
public class TestServiceResponseType {

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TestServiceRequestType", propOrder = {
"document"
})
public class TestServiceRequestType {

Once you do this, we can run the mvn test and it will work. If you notice in this example, we have tested the String WS end to end using JUnit and Spring Integraiton.

For further reading refer http://blog.springsource.org/2011/01/11/spring-web-services-2-0-released/ .


Published at DZone with permission of Krishna Prasad, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)