Testing Sequences in WSO2 ESB
Take a look at this project that presents use cases for testing sequences in WS02 ESB projects.
Join the DZone community and get the full member experience.
Join For Freethis post is intended to present a project that could help with testing the mediation sequences created in wso2 esb projects.
using tools like soap ui and postman, we can test our apis and proxies by issuing requests to them and validate the response of the services. as this gives us a good start point for testing the integrations, it doesn’t allow us to test the individual pieces that compose the integration, the mediation sequences.
thinking on that, the project wso2unittesting was created. the project was based on the following blog post .
the project consists of a car file that needs to be deployed to wso2 esb/ei server where the artifacts that need to be tested will be also deployed to. it provides an api that we will call in order to test the sequences.
the api receives a post request with a json payload that will contain the information required to test a sequence:
-
payload
: the payload that the sequence under testing is expecting to handle; -
requesttype
: the message type for the request payload, the input payload expected by the sequence, that can be xml or json; -
responsetype
: the message type for the response payload, the output payload after executing the sequence, that can be xml or json; -
properties
: the properties that sequence under testing is expecting to handle. -
sequences
: the name of the sequence that is going to be tested.
an example of a request can be seen below:
{
"payload" : "<abc xmlns=\"http://www.abc.com\"><text>123</text></abc>",
"requesttype": "xml",
"responsetype": "xml"
"properties": [
{
"name":"prop1",
"value": "abc",
"scope": "default",
"type":"string"
}
],
"sequences": [
"sequencefortest"
]
}
the response has a similar structure, the only difference being that it will contain the payload and properties generated after the execution of the sequence.
unit test example
as an example, we have built a sample app that is a simple rest api around a calculator soap service. for the sake of the simplicity, we have created just one resource,
/add
,
that receives two numbers and returns a json with the result of the sum.
the resource is composed by the following sequences:
-
unittestexample_validation_sequence
: it validates the resource parameters to check if they are numbers. it set a property
validation_result
that can befailure
orsuccess
. in case of validation failures, it sets another property,val_error_message
, with the failure message; - unittestexample_buildrequestpayload_sequence : it builds the request payload to the target backend system using the two parameters received;
- unittestexample_sendrequest_sequence : it sends the request to the target system using a call mediator;
- unittestexample_buildresponsepayload_sequence : it builds the json response with the result of the soap call to the target system;
the api code can be seen below:
<?xml version="1.0" encoding="utf-8"?>
<api context="/calculator" name="calculatorapi" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="get" uri-template="/add/{number1}/{number2}">
<insequence>
<!-- build request -->
<sequence description="validating the input data" key="unittestexample_validation_sequence"/>
<filter regex="failure" source="get-property('validation_result')">
<then>
<sequence key="unittestexample_buildfailureresponse_sequence"/>
</then>
<else>
<sequence key="unittestexample_buildrequestpayload_sequence"/>
<!-- send to service -->
<sequence key="unittestexample_sendrequest_sequence"/>
<sequence key="unittestexample_buildresponsepayload_sequence"/>
<!-- build response payload -->
</else>
</filter>
<log level="full">
<property expression="$ctx:validation_result" name="validationresult"/>
</log>
<!-- check if it was a failure - build error payload -->
<!-- else build request payload and send it -->
<respond/>
</insequence>
<outsequence/>
<faultsequence/>
</resource>
</api>
an example of the api call can be seen below:
http://localhost:8280/calculator/add/1/2
as we could see, it is a very simple example of a wso2 esb api.
let us now work on the unit tests for the sequences created for these examples.
pre-requisites for running the examples
in order to run the examples we need to:
-
clone the wso2unittesting project:
git clone https://github.com/fjunior87/wso2unittesting.git
-
build it:
cd wso2unittesting
;mvn clean install
- deploy the car file into the wso2 ei/esb. it will be under wso2unittesting/wso2unittestcompositeapplication/target;
-
clone the application example:
git clone https://github.com/fjunior87/wso2unittestexample.git
-
build it:
cd wso2unittestexample
;mvn clean install
- deploy the car file into the wso2 ei/esb. it will be under wso2unittestexample/wso2unittestexampleappcompositeapplication/target;
we also need the postman project that can be found in the example app: unittestexample.postman_collection.json.
you can import it to postman and then send the requests.
unit test using postman
for this post, i will use postman to issue the requests to our unittest api and to validate the response, as it supports tests.
for the first example, we will test the validation sequence for a success scenario. we can see the sequence code below:
<?xml version="1.0" encoding="utf-8"?>
<sequence name="unittestexample_validation_sequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<property description="get number1 value" expression="$ctx:uri.var.number1" name="number1_value" scope="default" type="string"/>
<property description="get number2 value" expression="$ctx:uri.var.number2" name="number2_value" scope="default" type="string"/>
<property name="validation_result" scope="default" type="string" value="success"/>
<filter regex="nan" source="string(number($ctx:number1_value))">
<then>
<property name="validation_result" scope="default" type="string" value="failure"/>
<property name="val_error_message" scope="default" type="string" value="number1 parameter is not a number"/>
</then>
<else/>
</filter>
<filter regex="nan" source="string(number($ctx:number2_value))">
<then>
<property name="validation_result" scope="default" type="string" value="failure"/>
<property name="val_error_message" scope="default" type="string" value="number2 parameter is not a number"/>
</then>
<else/>
</filter>
</sequence>
as we can see, the sequence expects two properties and validates if they are both numbers. below we can see what the payload would be to test the success scenario:
{
"payload" : "<empty/>",
"requesttype": "xml",
"responsetype": "xml",
"properties": [
{
"name":"uri.var.number1",
"value":"1",
"type": "string"
},
{
"name":"uri.var.number2",
"value":"2",
"type": "string"
}
],
"sequences": [
"unittestexample_validation_sequence"
]
}
let's describe the payload being passed for this test case:
-
payload
: we are passing an empty payload as this sequence doesn’t use any information of the payload; -
requesttype
andresponsetype
: we are setting xml; for this test case it is not relevant as we are not using the payload information; -
properties
: we are setting the two properties that the sequence is expecting to use: uri.var.number1 and uri.var.number2. we specify the type and the value for each of the properties; -
sequences
: we define the name of the sequence that we will be testing, in this case,unittestexample_validation_sequence
.
using the payload above we will make a request to the following endpoint:
http://localhost:8280/unittest/test
the response payload will look as below:
{
"payload": "<empty/>",
"requesttype": "xml",
"responsetype": "xml",
"properties": [
{
"name": "number1_value",
"value": "1",
"type": "string",
"scope": "default"
},
{
"name": "uri.var.number2",
"value": "2",
"type": "string",
"scope": "default"
},
{
"name": "validation_result",
"value": "success",
"type": "string",
"scope": "default"
},
{
"name": "uri.var.number1",
"value": "1",
"type": "string",
"scope": "default"
},
{
"name": "number2_value",
"value": "2",
"type": "string",
"scope": "default"
}
],
"sequences": [
"unittestexample_validation_sequence"
]
}
it will basically contain the payload generated and the properties set after the execution of the sequence. in this case, it contains the properties that were used by the sequence as well the properties set after it, the most important property for our testing being validation_result. looking into the response payload we can see it was set as
success
.
once we have the request and response, we can use postman test scripts to assert the properties set and also the payload generated.
pm.test("response is ok", function () {
pm.response.to.have.status(200);
});
pm.test("validation_result is success", function () {
json = pm.response.json();
var prop = json.properties.find(prop => prop.name == 'validation_result' && prop.scope == 'default');
pm.expect(prop.value).to.equal("success");
});
basically, this test is validating whether the status code is 200 and if the property
validation_result
is equals
success
.
we can see an example of this test case execution below:
as we could see with this test, we were able to execute a sequence from our application passing all the expected properties.
in the next test case, we will see an example of test passing an expected payload to a sequence.
in the test below, we will be testing the sequence that generates the response payload based on the response got from the backend call. the test request can be seen below:
{
"payload" : "<addresponse xmlns=\"http://tempuri.org/\"><addresult>30</addresult></addresponse>",
"requesttype": "xml",
"responsetype": "json",
"properties": [],
"sequences": [
"unittestexample_buildresponsepayload_sequence"
]
}
in this test, we are not setting any property as it is not expected by the sequence being tested. we set only:
-
payload
: the xml expected by the sequence; -
requesttype
: xml, as the input payload is an xml; -
responsetype
: json, as the output payload is a json;
by executing this request we will receive a response like below:
{
"payload": "{\n\t\t\t\t\"result\": 30\n\t\t\t}",
"requesttype": "xml",
"responsetype": "json",
"properties": [],
"sequences": [
"unittestexample_buildresponsepayload_sequence"
]
}
and our postman test will look like this:
pm.test("response is ok", function () {
pm.response.to.have.status(200);
});
pm.test("response payload should have the result equals to 30", function () {
json = pm.response.json();
payload = json.parse(json.payload);
pm.expect(payload.result).to.equal(30);
});
that’s it for today.
in the postman project, there are a couple of other test cases. if you want, you can also run the postman tests in the command line using newman . also, you could create your test cases using any other testing tool/framework like soapui, restassured, or karate.
the source code of the unit test app and the example app can be found here and here .
i hope you enjoyed and that this will help you to increase the quality of your wso2 ei projects!
see you in the next post.
Published at DZone with permission of Francisco Ribeiro, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments