GrabDuck

Spring Controller Tests 2.0 - Jayway

:

Spring has many tools in the toolbox to facilitate testing. However, when it comes to testing a Controller, the tools have been a bit blunt. To make life easier, Sam Brennan and Rossen Stoyanchev presented the spring-test-mvc framework during a session at SpringOne 2GX last year. It provides a Java DSL that enables white box Controller testing of request mappings, response codes, type conversions, redirects, view resolutions, and more. This post will briefly introduce how a Spring powered REST Controller test may be implemented when written as a standalone test with Mockito used as mocking framework.

Example Controller

Let’s assume that you have a simple UserController class with just a single method:

As can be seen, the getUser(long userId) method is mapped to GET requests of the /user/{userId} URL. When a request is executed, the method fetches information about a User from the UserService and serializes the result to JSON or XML depending on the accept header of the request.

Test

We start by verifying that we can fetch a user serialized to JSON. In plain English, we would like the following test:

Perform a GET request to /user/0
with JSON as accepted media type,
then expect the status code to be ok,
the content type of the response to be of type JSON,
the response body to have an expected “name” key/value pair
and an expected “email” key/value pair.

Compare with spring-mvc-test implementation below:

Setup

In order for the test to work, we need to create a setup method:

The first few lines should be familiar to all Mockito users. Basically, a UserService instance is created by calling the Mockito.mock(Class classToMock) method. A testUser instance is created, and the mock is instructed to return it. Next the UserController to be tested is instantiated using the mock service.

The last lines of the setup method contains the new MockMvc class. It is created by calling a factory method on the builder class MockMvcBuilders. In this example, we choose the standalone option to which the UserController instance is passed. Alternatively, there are other factory methods available that creates a MockMvc from a web application context, an XML application configuration or a Java based application configuration.

More tests

With some minor changes of the test method (change the media type to XML and use xpath instead of jsonPath to extract the response data), it can be verified that the Controller can return a user as an XML document:

To make sure that clients cannot update a user, another test is created that verifies that POST is not permitted. (The allow header is part of the HTTP spec and added to the response header by Spring. Depending on your business case you may choose to ignore that expectation.):

Debugging

Sometimes it can be a bit hard to debug a test if an expectation fails. On those occasions, it can be beneficial to print some information to find out what is going on:

When executed, the test prints information about the request and response to the console. Notably, it also prints information about handler type and handler methods. Due to the simple nature of this example, many of the lines are left blank, but it gives you some indication to what can be verified in other tests:

For reference, click on the links to get the complete implementation of the UserControllerTest and the User class.

Dependencies

In the spring-mvc-test read-me file, it is stated that:

This code will be included in the spring-test module of the Spring Framework.

Consequently the project will be moved, hopefully as part of the upcoming Spring 3.2 release, and then the spring-test dependency can be used. However, currently there is a milestone release available in the Spring maven milestone repository. For the tests described above, you also need to add Mockito and JsonPath to your pom:

Alternatives

Another framework that partly solves the same problem is REST Assured. In comparison to the spring-mvc-test it offers a Java DSL for web based testing, but it focuses on integration testing of a running REST server, e.g. it is not possible to mock Controller dependencies or to validate specific Spring objects that are used internally by the application. On the other hand, it offers features like OAuth authentication and SSL support.

References

Edit

Nov 12th, 2012: Updated code examples to reflect the changes in the Spring Framework 3.2 RC1 Release. For more information, read Rossen Stoyanchev’s blog post about the Spring MVC Test Framework.