Writing junit test case to test Mule flow
- Get link
- X
- Other Apps
Hello Coder,
In my last post we learned to create a SOAP server in Mule. We created a Mule flow and ran it inside Anypoint studio. As the flow grows there is more need of unit as well as integration testing. Testing of a service/dao or any other component is fairly simple, in complex scenarios where services are injected using Spring there we can mock the services and inject them while running a JUnit test case. But how can we test a mule-flow xml and ensure that everything works as expected ?
In this post we will learn to write a JUnit test case to test your Mule flow. We will use mule's testing framework to create test classes. In order to proceed you need to have basic knowledge about JUnit test cases and you should know how mule flow works. We will write the test case for the flow mentioned in our previous post mentioned here.
In order to have a completely working test case we need to update the mule flow of this post to have an Implementation class of the soap service interface which will return the doubled value of the request. To add a Impl class, create a class DoubleItPortTypeImpl which will implement the SOAP service. We will verify this test case from the results returned by this implementation class.
Lets add this service implementation in our flow by adding a Java component after the SOAP connector. This Java connector will be executed after the SOAP connector processes the incoming request by transforming it to a JAXB request object.
Open the mule flow in "Message Flow" view of Anypoint studio.
Now search the keyword "Java" in the right pane of Studio. Select the Java component from "Components" tab and drag it to flow after SOAP connector. Like this:
Now click on the Java component in the flow and go to "Mule properties view". Give the fully qualified class name of your impl class under the "Class Name:" box. Save the flow xml.
Adding a Java component will generate the following xml in the flow:
This Java component will be called by the SOAP connector once request is processed at SOAP connector. The SOAP connector will prepare a JAXB message from the incoming request and pass it the the Java connector. Since the Java connector is configured with the implementation class of our service hence CXF connector will call appropriate method according to the SOAP request.
Here is the full xml for our complete flow:
<?xml version="1.0" encoding="UTF-8"?> <mule xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.6.0" 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-current.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd"> <http:listener-config name="Connector_Config" host="localhost" port="8090" doc:name="HTTP Listener Configuration" basePath="mulesvc"/> <flow name="soap-webservice-muleFlow"> <http:listener config-ref="Connector_Config" path="sample/soapws/DoubleIt.svc" doc:name="HTTP"/> <cxf:jaxws-service service="DoubleIt.svc" serviceClass="com.sample.mule.DoubleItPortType" doc:name="CXF" wsdlLocation="C:\Mule-workspace\workspace\soap-ws-mule\src\main\resources\example-soap-ws.wsdl"/> <component class="com.sample.mule.impl.DoubleItPortTypeImpl" doc:name="Java"/> </flow> </mule>
Now we have a complete flow with a implementation class for SOAP service. We are good to start writing the test case now.
Mule provides org.mule.tck.junit4.FunctionalTestCase
class which is the base test case class for all the test cases. This class will initialize mule and loads the flow(s) by provided flow file. By default SpringXmlConfigurationBuilder configuration builder is used.
If you want to use other builder than SpringXmlConfigurationBuilder then you should override the getBuilder() of this class.
Note: In order to use this class to create test cases make sure mule-modules-builders jar exists on your mule application's classpath.
Lets create a test class by extending FunctionalTestCase and put it under test/java of our mule application. After creating the test class we need to write a test method where we can test the flow. Lets say we write a test method testSOAPResponse()
and annotate it with @Test
. @Test is annotation provided by JUnit library and if it is annotated on a method than that method will be marked as a test method by JUnit framework.
In the test class we need to override the getConfigFiles()
method of FunctionalTestCase
. This method should return an array of mule flow file(s) which we need to test. In our case we have only 1 flow file hence we will add this file's relative path in the String array and return it.
Next, we need to create a xml file for the request of Mule flow. Create a xml file and put it under src/test/resources
say sample
of your project. Now in the test method read the xml file in String using the readFile()
method shown below.
Once we have the String xml we can start invoking the flow. We will write a simple HTTP client which will send a request on the same url on which our Mule flow listens. See the method getResponseAfterMuleFlowExecution()
where we first create a HTTP client and then set its url to our flow's inbound endpoint. Since it is a SOAP request hence we need to set the content-type to application/soap+xml
. Now create a POST method and invoke our flow's endpoint. The HTTP client will actually make a call to the provided url and then, since the url points to a SOAP endpoint in flow, the flow execution starts. You can put a logger component in the Mule flow to see if the flow is actually called by the HTTP client from the test case.
Once the flow is called from the test method, the request will pass from all the components in the flow and finally a response is sent back by the HTTP connector. The final response from this is the response generated by the last component in the flow i.e. Java component for service implementation. So whatever this component returns is the same returned by the HTTP connector. In our test method we will receive the response from the Mule flow.
In our test method we need to parse the String response to proper Java object using JAXB unmarshaller. We will unmarshall the original request and the response from Mule flow. After unmarshalling we can Assert the results from Request and Response. Below is the full working test case for testing our SOAP service mule flow.
package com.sample.test; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPMessage; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.junit.Assert; import org.junit.Test; import org.mule.tck.junit4.FunctionalTestCase; import org.springframework.core.io.ClassPathResource; import com.sample.mule.DoubleIt; import com.sample.mule.DoubleItResponse; public class MuleFlowTest extends FunctionalTestCase { private static final String MULE_FLOW_URL = "/mulesvc/sample/soapws/DoubleIt.svc"; private static final String MULE_ENDPOINT = "http://localhost:8090"; @Override protected String[] getConfigFiles() { String[] configFile = new String[] {"soap-webservice-mule.xml"}; //It should be relative path to your flow xml file return configFile; } @Test public void testSOAPResponse() throws Exception { String requestXml = readFile("sample/doubltItRequest.xml"); String doubleItResponse = getResponseAfterMuleFlowExecution(requestXml); if (doubleItResponse != null) { SOAPMessage requestMessage = MessageFactory.newInstance().createMessage(null, new ClassPathResource("sample/doubltItRequest.xml").getInputStream()); InputStream is = new ByteArrayInputStream(doubleItResponse.getBytes()); SOAPMessage responseMessage = MessageFactory.newInstance().createMessage(null, is); JAXBContext jaxbContext = JAXBContext.newInstance(DoubleIt.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); DoubleIt request = (DoubleIt) jaxbUnmarshaller.unmarshal(requestMessage.getSOAPBody().extractContentAsDocument()); jaxbContext = JAXBContext.newInstance(DoubleItResponse.class); jaxbUnmarshaller = jaxbContext.createUnmarshaller(); DoubleItResponse response = (DoubleItResponse) jaxbUnmarshaller.unmarshal(responseMessage.getSOAPBody().extractContentAsDocument()); Assert.assertEquals(response.getDoubledNumber(), request.getNumberToDouble()*2); } Assert.assertNotNull(doubleItResponse); } private String readFile(String resourcePath) throws IOException { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new FileReader(new ClassPathResource(resourcePath).getFile()))) { String sCurrentLine; while ((sCurrentLine = br.readLine()) != null) { sb.append(sCurrentLine); } } catch (IOException e) { Assert.fail(); } return sb.toString(); } protected String getResponseAfterMuleFlowExecution(String xmlRequest) throws Exception { String url = MULE_ENDPOINT + MULE_FLOW_URL; HttpClient httpClient = new HttpClient(); httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(10000); PostMethod postMethod = new PostMethod(url); postMethod.addRequestHeader(org.apache.http.HttpHeaders.ACCEPT, "application/soap+xml"); postMethod.setRequestEntity(new StringRequestEntity(xmlRequest, "application/soap+xml", StandardCharsets.UTF_8.name())); httpClient.executeMethod(postMethod); return postMethod.getResponseBodyAsString(); } }
Now run this class as junit test case from Anypoint studio. For it you need to right click on the file and then select "Run As" and then select "JUnit test". You can see debug the request and response and check if the data is getting doubled by the soap service and is being returned correctly in the response. The FunctionalTestCase class will load the Mule flow from the xml file which we provide in the overidden method getConfigFiles(). You can specify as many flow files as you want to load them in the test case.
And we are done with writing a JUnit test case in Mule. Hope it helps
- Get link
- X
- Other Apps
Comments
we are offering best mulesoft online training in hyderabad with job support and high quality training facilities and well expert faculty .
ReplyDeletemulesoft training in hyderabad
the blog is good and Interactive it is about Mulesoft Anypoint Studio it is useful for students and Mulesoft Developers for more updates on Mulesoft mulesoft Online training bangalore
ReplyDelete