Performing Integration or System Tests can be a hard task at times. A few days back I was presented with the challenge of performing testing with two heterogeneous environments, using different interfaces, SOAP and REST respectively. There are some silver bullets to perform testing REST-based environments, such as RestAssured, Karate Framework or even TestNG with Apache HTTP Client. For SOAP the options are usually rather limited, so I decided to investigate even further. I stumbled upon Citrus Framework as it seemed to provide a fair support to SOAP messages. Since it supports REST as well, it seemed to be a very nice fit for this particular case where I had to perform System-wide tests on both interfaces at the same time. I decided to give it a try.
I’ll cover the setup for REST-based tests since it is faster to have it set up locally. I will provide the instructions for SOAP at the very end, so please bear with me 😉
To start with, we need some sort of server that allows us to exchange messages with. So let’s set up a quick one and focus more on the client-side that relates to testing it.
Setup a project folder for this demo-session: citrus-tests, and execute the next steps inside this folder.
Let’s install a local version of JSONPlaceholder. The pre-requirements are:
- Node v.6.10.2
- npm 3.10.10
Once you have these setup, please run:
The json-server will not be installed directly in this folder, but the npm console will allow us to launch it. As soon as the setup is successfully completed, start the server using:
The file db.json will be saved in your project folder.
If everything is properly set up, go to http://localhost:3000 and you will see the JSONPlaceholder’s home page. Leave it running in the background. You may want to open another shell in our project folder.
At this point, we have the server side setup and we can start with the client-side tests. It should have taken less than 3 minutes so far.
Getting started with Citrus is easy since it provides some Maven Archetypes to bootstrap the project quicker. Let’s create it via:
Choose the following options in the interactive menu:
It should match to:
In the next prompt, we should enter the Citrus version that we would like to use – Let’s choose the latest version available, 2.7.2 as of writing this post.
Next, we’re asked to define some project-specific properties:
From this point on, you can choose the default options pressing <Enter>.
Seeing BUILD SUCCESS means the archetype ran properly and the project base is created.
Now, If you call:
You should see that some tests are executed. These come along with the base project and can be safely deleted, but they provide some basic guidance about the overall project structure.
Question: Why did we run mvn clean verify instead of mvn clean test? If I execute mvn clean test I see that the build succeeds but no tests are executed, why is that?
Answer: That’s because Citrus Tests are meant to be used by integration tests which are bound to the verify phase. Other frameworks like JUnit for example are initially designed to work with the test phase. More on that can be found on Maven’s Documentation, alongside Surefire and Failsafe, the Maven plugins for running Unit and Integration tests, respectively.
Now is the time to start setting up our Test Suite. The first thing you need to take under consideration is that Citrus uses Spring Dependency Injection (DI) and therefore we need to setup the Application Context. This will allow us to have a REST client ready to be used without writing one single line of boilerplate code.
Open the file src/test/resources/citrus-context.xml and add the following content:
This is where the Spring DI comes into the picture. It will setup an HTTP client for our tests automatically with the name restClient, so we can use it directly on the testing code. It already points to our running local server.
The next step is to create our Test class, where the magic will happen. Create a new file named CitrusDemoIT.java under src/test/java/io/testproject/. This class must extend TestNGCitrusTestDesigner so we can make use of the Citrus Context properly.
Note: It is important to stick to the name convention of having the file name terminating with *IT.java, otherwise the test class will not be executed by the surefire plugin. This can be seen between the lines 116-143 in the pom.xml for further clarity.
Let’s add the restClient created in the citrus-context.xml to our Test Class.
This should be all the groundwork needed. Let’s create our first Test method now:
Here are some brief remarks:
- @Test is a TestNG annotation, and priority property will help us run the test methods in the right sequence.
- @CitrusTest is a Citrus annotation that allows us to use the Citrus Context and its fully-fledged features.
- Citrus has a very nice DSL syntax that allows us to describe the client’s actions.
Now, if we run mvn clean verify we should see that our Test Method is being executed.
So far, we have covered how to:
- Setup a quick server for our test scenario.
- Use Citrus Maven archetype to bootstrap the project quicker.
- Setup our Application Context that abstracts the boilerplate code.
- Setup our Test Class and initial Test Method.
- Execute the Test Suite.
However, our test method isn’t doing much yet, so let’s add some juice to it and make it smarter. Differently than the majority of frameworks, Citrus works with a 2-fold reply-response method – this is my own naming convention for it. It means that with the code we have covered so far, we can’t verify whether the request was properly digested by the client, so we don’t know if the server is working as expected.
Now, we’ll verify the response data using the following code that needs to be added to our existing test method:
Let’s run mvn clean verify again and check the output.
Here, we have our first test failure.
This well-designed summary is a feature I like on Citrus Framework, since it abstracts the relevant bits of the stacktrace and provides a relevant excerpt about the failure. You are welcome to see the full content of the stacktrace by rolling up the full log output. It turns out to be a big time saver when troubleshooting extensive test suites with multiple scenarios.
Back to the test scenario – Our server is behaving properly since the REST interface semantic stimulates developers to use the proper HTTP codes when creating resources, so in this case the server is yielding 201 – CREATED as it should be.
Let’s adjust our test method. It should look like this:
If we want to break it down into GIVEN/WHEN/THEN/VERIFY sections it would look like this:
The beauty of DSL is that by reducing the code footprint, we’re able to focus on the test behavior instead of handling boilerplate code. Furthermore, we can break down the code into more readable statements.
Back to the testing business, now we have a rough Test Suite that will enable us to verify if the /posts endpoint is doing its basic job properly. If at any point there is a server timeout or the business logic breaks, our tests would be able to report that at a timely manner.
I’ll end the tutorial part here, but you are welcome to check the Citrus Samples in Github, and check some more advanced scenarios on how we can use JSON templates and how we can use Groovy code together with Citrus – This unleashes a whole lot of new possibilities as well!
What is your impression of the Citrus Framework? Please share your thoughts in the comment section below!