Friday, August 12, 2016

Writing integration tests for Apache CXF REST API that supports XML and JSON

Hey folks,

This comes up as a part of my ongoing GSoC project. The task as described in an earlier post was simple. To convert a SOAP service to REST. Yet the individual issues that comes up along the way sums up to writing those separate blog posts about them.

So this is the last phase of the project that I'm currently carrying out, that is to write integration tests for the now available REST web service. Now have the following assumptions before we go through the procedure

1) The service is implemented with Apache CXF and JAX-RS
2) It can consume and produce both XML and JSON based requests and responses
3) Service is up and running and accessible at https://localhost:5000/rest
4) Service has a one service method called getResponse that accepts XML or JSON requests (in a predefined way) and outputs according to the headers given.


Issue now is that although we can easily write unit tests for any given piece of code, writing unit tests for the web service api is just pointless. We need to be able to test the service online it self whenever we make a change to see that everything works good (the whole point of testing). So what we need are integration tests.
Moreover since my request/response architecture supports XML and JSON I should be able to send corresponding requests and check if I am getting the desired responses. So let's dig into the steps.


1) Add all dependencies

We need 2 things for our code to work
i) Apache CXF
ii) TestNG (Or if you preper you can use JUnit as well)

Since my project is all maven based, I will show how to add the required dependencies using maven. If you use any other dependency management software, feel free to find the libraries appropriately.

2) Prepare the directory structure

Before going into code we need to structure our codes so that the test classes doesn't mess up with our source code. Also keep in mind that since we have to test XML/JSON requests/responses we need to store these code files somewhere and read them as well. Hardcoding them inside the test classes would be an ugly option. So we have 3 things to keep apart from each other
i) Source code
ii) Test classes
iii) XML/JSON codes

Here's how I managed to seperate those

There are 2 main directories under the src directory
i) main : contains source code and it's resources
ii) test : contains test classes and it's resources

Since XML/JSON codes are part of the test classes, they are put within the resources directory under test directory.

3) So now we are ready to start with the code. First make a single class named TestService which extend Assert class under the test directory. (Chose the package names appropriately)

4) First we write a simple method to check if the service is online, if it's offline we cannot do any integration test on it.

If your service is secure (https), then probably the java WebClient will need to verify the certificates before any request can be made. If such verification cannot be done, an exception would occur. The easiest way to overcome is to make up your own keystore and specify the path to the keystore or truststore from the code. You can easily google that step, anyhow I added the following to the constructor of TestService class to mention the location of the trustStore to the WebClient. (This corresponds only according to my own configuration)

5) Everything's ready to go but we need to make some mock XML/JSON requests and responses first.



Keep those files in the xml directory under the resources.
Assume that when we send the contents of request-getResponse-1.xml over to the getResponse service method, we receive the response with the content in response-getResponse-1.xml.

6) Next we need a method to read the content from those 2 files. Here's a neat method that does the job, note that the string replacement at the end makes sure that things work correctly when we have to do assertEqual at the desired and actual responses at the end.

7) Let's write our first test method now
You can change / add / remove the headers as necessary, and keep in mind that this suits to a service method that reads the body of the request and processes it. If you play around a bit you can find the way to send any type of request to a service.

8) Here's the full code when all put together, and now you test the code. And TA-DAA
All test cases passed!

If you get any test case failures check the outputs of response and webResponse to see what's going wrong. So happy testing!