Others


How jsonpath can help you to test rest controllers?

Introduction

In this post, I will show how you can write assertions to json strings.
When I test my rest controllers, I want to check that responses bodies contains exactly the json that I assume.

Json path is a tool which can return you only the part of json that you want.
You give it a pattern to express which part of data you want to receive.

JsonPath patterns

I have the following json:

[
	{
		"name":"Lukas",
		"age":23
	},
	{
		"name":"Jack",
		"age":35
	},
	{
		"name":"Michael",
		"age":32
	}
]

When I use pattern:

$[0].name

I receive a string:
“Lukas”
When pattern will be:

$.[1].age

Result:
35

You can see that expressions are something like regexp for json.

Java tests examples

Ex.1
Lets assume that our controller should return json similar to this:

{
	“id”:12
}

when we request it by -> /user/12

@Test
public void shouldReturnUserWithId() throws Exception {
   String responseContent = mockMvc.perform(get("/user/" + USER_ID).accept(MediaType.APPLICATION_JSON_UTF8))
           .andExpect(status().isOk())
           .andReturn().getResponse().getContentAsString();

   Integer loginFromResponse = JsonPath.parse(responseContent).read("$.id");
   Assert.assertEquals(USER_ID, loginFromResponse.intValue());
}

Ex.2
We assume that json should be an object with array of objects with “id” property.

{
	[
{	
	“id”:1
},
{	
	“id”:2
},
{	
	“id”:3
}
	]
}
@Test
public void shouldReturnArrayOfUsers() throws Exception {
   String responseContent = mockMvc.perform(get("/user").accept(MediaType.APPLICATION_JSON_UTF8))
           .andExpect(status().isOk())
           .andReturn().getResponse().getContentAsString();

   List<Integer> ids = JsonPath.parse(responseContent).read("$[*].id");
   MatcherAssert.assertThat(ids, Matchers.hasSize(3));
   MatcherAssert.assertThat(ids, Matchers.containsInAnyOrder(1,2,3));
}

As you can see, we can use hamcrest mathers to test collection returned by jsonpath api.

Ex.3

@Test
public void shouldReturnsUsersWithListsOfPosts() throws Exception {
   String responseContent = mockMvc.perform(get("/user").accept(MediaType.APPLICATION_JSON_UTF8))
		   .andExpect(status().isOk())
		   .andReturn().getResponse().getContentAsString();

   List<String> postTitles = JsonPath.parse(responseContent).read("$[*].posts[0].title");
   MatcherAssert.assertThat(postTitles, Matchers.hasSize(3));
   MatcherAssert.assertThat(postTitles, Matchers.everyItem(Matchers.is("post1")));
}

Here is shown that you can easily extract repeatedly nestet items.

Tools

To test your jsonpath expression you can testers which are many on the internet.
Here you can find one of them:
https://jsonpath.curiousconcept.com/

Links

https://github.com/jayway/JsonPath
https://github.com/raphaelsolarski/jsonpath-to-test-rest-controller-example