Using JsonPath and XmlPath in REST Assured
This post was published on April 26, 2017While preparing my REST Assured workshop for the Romanian Testing Conference next month, I ran into a subject I feel I didn’t cover enough in the previous times I hosted the workshop: how to effectively use JsonPath and XmlPath to extract specific elements and element groups in RESTful API responses before verifying them. Here are a couple of tricks I learned since and worked into the exercises that’ll be part of the workshop from now on.
The examples in this post are all based on the following XML response:
<?xml version="1.0" encoding="UTF-8" ?> <cars> <car make="Alfa Romeo" model="Giulia"> <country>Italy</country> <year>2016</year> </car> <car make="Aston Martin" model="DB11"> <country>UK</country> <year>1949</year> </car> <car make="Toyota" model="Auris"> <country>Japan</country> <year>2012</year> </car> </cars>
The syntax for JsonPath is very, very similar, except for the obvious lack of support for attributes in JsonPath (JSON does not have attributes).
Extracting a single element based on its index
Let’s get started with an easy example. Say I want to check that the first car in the list is made in Italy. To do this, we can simply traverse the XML tree until we get to the right element, using the index [0] to select the first car in the list:
@Test public void checkCountryForFirstCar() { given(). when(). get("http://path.to/cars"). then(). assertThat(). body("cars.car[0].country", equalTo("Italy")); }
Similarly, we can check that the last car came on the market in 2012, using the [-1] index (this points us to the last item in a list):
@Test public void checkYearForLastCar() { given(). when(). get("http://path.to/cars"). then(). assertThat(). body("cars.car[-1].year", equalTo("2012")); }
Extracting an attribute value
Just as easily, you can extract and check the value of an attribute in an XML document. If we want to check that the model of the second car in the list is ‘DB11’, we can do so using the ‘@’ notation:
@Test public void checkModelForSecondCar() { given(). when(). get("http://path.to/cars"). then(). assertThat(). body("cars.car[1].@model", equalTo("DB11")); }
Counting the number of occurrences of a specific value
Now for something a little more complex: let’s assume we want to check that there’s only one car in the list that is made in Japan. To do this, we’ll need to apply a findAll filter to the country element, and subsequently count the number of items in the list using size():
@Test public void checkThereIsOneJapaneseCar() { given(). when(). get("http://path.to/cars"). then(). assertThat(). body("cars.car.findAll{it.country=='Japan'}.size()", equalTo(1)); }
Likewise, we can also check that there are two cars that are made either in Italy or in the UK, using the in operator:
@Test public void checkThereAreTwoCarsThatAreMadeEitherInItalyOrInTheUK() { given(). when(). get("http://path.to/cars"). then(). assertThat(). body("cars.car.findAll{it.country in ['Italy','UK']}.size()", equalTo(2)); }
Performing a search for a specific string of characters
Finally, instead of looking for exact attribute or element value matches, we can also filter on substrings. This is done using the grep() method (very similar to the Unix command). If we want to check the number of cars in the list whose make starts with an ‘A’, we can do so like this:
@Test public void checkThereAreTwoCarsWhoseMakeStartsWithAnA() { given(). when(). get("http://localhost:9876/xml/cars"). then(). assertThat(). body("cars.car.@make.grep(~/A.*/).size()", equalTo(2)); }
If you know of more examples, or if I missed another example of how to use JsonPath / XmlPath, do let me know!
"