Today we’re going to take a look at two specific frameworks that enables you to efficiently test your REST-ful services: On the one side there is the framework REST-assured that offers a nice DSL-like syntax to create well readable tests – on the other side there is the Jersey-Test-Framework that offers a nice execution environment and is built upon the JAX-RS reference implementation, Jersey.

rest service testing logo

In the following tutorial we’re going to create a simple REST service first and then implement integration tests for this service using both frameworks.

The title of this article might be misleading due to the fact that I am not going to compare both frameworks to choose a winner, just showing the different approach ..

Prerequisites

Only JDK and Maven needed here …

Creating a new Maven project

A new Maven project is our first step for the following tutorial ..

  • Create a new Maven project with your favourite IDE and Maven plugin installed or via console using

    mvn archetype:generate
  • That’s all for now :)

The REST Service to be tested

First we need a REST service to write some tests for .. luckily that’s done with a few steps using JAX-RS ..

  • First we’re adding some dependencies for Jersey, JAX-B and Jersey-JSON to our pom.xml

    <dependencies>
    	<dependency>
    		<groupId>com.sun.jersey</groupId>
    		<artifactId>jersey-server</artifactId>
    		<version>1.9</version>
    	</dependency>
    	<dependency>
    		<groupId>javax.xml.bind</groupId>
    		<artifactId>jaxb-api</artifactId>
    		<version>2.2.4</version>
    	</dependency>
    	<dependency>
    		<groupId>com.sun.xml.bind</groupId>
    		<artifactId>jaxb-impl</artifactId>
    		<version>2.2.4</version>
    	</dependency>
    	<dependency>
    		<groupId>com.sun.jersey</groupId>
    		<artifactId>jersey-core</artifactId>
    		<version>1.9</version>
    	</dependency>
    	<dependency>
    		<groupId>com.sun.jersey</groupId>
    		<artifactId>jersey-json</artifactId>
    		<version>1.9</version>
    	</dependency>
    </dependencies>
    <repositories>
    	<repository>
    	    <id>maven2-repository.dev.java.net</id>
    	    <name>Java.net Repository for Maven</name>
    	    <url>http://download.java.net/maven/2/</url>
    	    <layout>default</layout>
    	</repository>
    	<repository>
    	    <id>maven-repository.dev.java.net</id>
    	    <name>Java.net Maven 1 Repository (legacy)</name>
    	    <url>http://download.java.net/maven/1</url>
    	    <layout>legacy</layout>
    	</repository>
    </repositories>
  • In the next step we’re creating our exported service method in a class named UserService

    package com.hascode.tutorial.rest;
    
    import java.util.Date;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    @Path("/user")
    public class UserService {
    	@GET
    	@Produces(MediaType.APPLICATION_JSON)
    	@Path("/id/{id}")
    	public User findById(@PathParam("id") final Long id) {
    		if (id.equals(666l)) {
    			return null;
    		}
    		final User user = new User();
    		user.setId(id);
    		user.setFirstName("Tim");
    		user.setLastName("Tester");
    		user.setBirthday(new Date(1321009871));
    		return user;
    	}
    }
  • The service exports a User object as a JSON structure .. this is done via @Produces(MediaType.APPLICATION_JSON)

  • Now we need the user object .. the mapping to JSON is done using JAX-B – the only thing we need is one annotation, @XmlRootElement

    package com.hascode.tutorial.rest;
    
    import java.util.Date;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class User {
    	private Long id;
    	private String firstName;
    	private String lastName;
    	private Date birthday;
    
    	// getter + setter
    }
  • Finally we’re adding the following web.xml to the directory src/main/webapp/WEB-INF

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <servlet>
            <servlet-name>Jersey REST Servlet</servlet-name>
            <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
            <init-param>
                <param-name>com.sun.jersey.config.property.packages</param-name>
                <param-value>com.hascode.tutorial.rest</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Jersey REST Servlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    </web-app>
  • Now we’re starting the rest service with an embedded tomcat instance using

    mvn tomcat:run
  • We’re able to run the REST service by calling the following url http://localhost:8080/rest-test-tutorial/user/id/12

  • The service returns the following JSON code

    {
    	"birthday":"1970-01-16T07:56:49.871+01:00",
    	"firstName":"Tim",
    	"id":"12",
    	"lastName":"Tester"
    }
  • Keep the embedded tomcat process running .. we’re going to need it for our integration tests later ..

Testing the Service

Now that we’ve got a nice, running REST service we want to test the exported service methods and data we’re getting from the service..

Using REST-assured

The first candidate for writing an integration test here is REST-assured ….

  • First we’re adding the dependencies for the REST-assured framework to our pom.xml

    <dependency>
    	<groupId>com.jayway.restassured</groupId>
    	<artifactId>rest-assured</artifactId>
    	<version>1.2.3</version>
    </dependency>
  • That’s what our integration test looks like

    package com.hascode.tutorial.rest;
    
    import static com.jayway.restassured.RestAssured.expect;
    import static com.jayway.restassured.RestAssured.get;
    import static org.hamcrest.Matchers.equalTo;
    import static org.hamcrest.Matchers.nullValue;
    
    import org.junit.Test;
    
    public class UserServiceTestUsingRestAssured {
    	@Test
    	public void testUserFetchesSuccess() {
    		expect().
    			body("id", equalTo("12")).
    			body("firstName", equalTo("Tim")).
    			body("lastName", equalTo("Tester")).
    			body("birthday", equalTo("1970-01-16T07:56:49.871+01:00")).
    		when().
    			get("/rest-test-tutorial/user/id/12");
    	}
    
    	@Test
    	public void testUserNotFound() {
    		expect().
    			body(nullValue()).
    		when().
    			get("/rest-test-tutorial/user/id/666");
    	}
    }
  • For more detailed information on the testing and matcher api, take a look at the documentation on the rest-assured website

  • That what my JUnit Runner in Eclipse looks like ;)
    rest assured junit screenshot

  • Update: I have written a complete and detailed tutorial covering the different features of the REST-assured framework and added a RESTful web service to run the tests from the tutorial against it: “Testing RESTful Web Services made easy using the REST-assured framework”

Using Jersey-Test-Framework

Now let’s try Jersey ..

  • We need some dependencies for the jersey-test-framework so we’re adding them to our pom.xml

    <dependency>
      <groupId>com.sun.jersey.jersey-test-framework</groupId>
      <artifactId>jersey-test-framework-core</artifactId>
      <version>1.9</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey.jersey-test-framework</groupId>
      <artifactId>jersey-test-framework-external</artifactId>
      <version>1.9</version>
    </dependency>
  • That’s how our integration test looks like

    package com.hascode.tutorial.rest;
    
    import static org.junit.Assert.assertEquals;
    
    import java.net.URISyntaxException;
    
    import org.codehaus.jettison.json.JSONException;
    import org.codehaus.jettison.json.JSONObject;
    import org.junit.Test;
    
    import com.sun.jersey.api.client.UniformInterfaceException;
    import com.sun.jersey.api.client.WebResource;
    import com.sun.jersey.test.framework.AppDescriptor;
    import com.sun.jersey.test.framework.JerseyTest;
    import com.sun.jersey.test.framework.WebAppDescriptor;
    
    public class UserServiceTestUsingJerseyTestFramework extends JerseyTest {
    	@Override
    	protected AppDescriptor configure() {
    		return new WebAppDescriptor.Builder().build();
    	}
    
    	@Test
    	public void testUserFetchesSuccess() throws JSONException,
    			URISyntaxException {
    		WebResource webResource = client().resource("http://localhost:8080/");
    		JSONObject json = webResource.path("/rest-test-tutorial/user/id/12")
    				.get(JSONObject.class);
    		assertEquals("12", json.get("id"));
    		assertEquals("Tim", json.get("firstName"));
    		assertEquals("Tester", json.get("lastName"));
    		assertEquals("1970-01-16T07:56:49.871+01:00", json.get("birthday"));
    	}
    
    	@Test(expected = UniformInterfaceException.class)
    	public void testUserNotFound() {
    		WebResource webResource = client().resource("http://localhost:8080/");
    		JSONObject json = webResource.path("/rest-test-tutorial/user/id/666")
    				.get(JSONObject.class);
    	}
    }
  • More detailed information on the jersey-test-framework can be found at its project website or Naresh’ blog. The real strength of the Jersey-Test-Framework lies in its capability to start different types of containers to create a test environment for your rest service – we don’t use this nice feature here and could have also simply created a Jersey client using Client client = Client.create() and parsed the response …

  • Running the sample code in your IDE your JUnit view might look like this one
    jersey test framework junit

Tutorial Sources

I have put the source from this tutorial on my GitHub repository – download it there or check it out using Git:

git clone https://github.com/hascode/rest-test-tutorial.git

Troubleshooting

  • Caused by: com.sun.jersey.api.MessageException: A message body writer for Java class …, and Java type class…, and MIME media type application/json was not found” – The dependency for jersey-json is missing .. just add the following dependency to your pom.xml

    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-json</artifactId>
      <version>1.9</version>
    </dependency>

Article Updates

  • 2015-08-06: Links to other REST articles of mine added.

  • 2015-10-22: Link list updated.