Guide to Jersey Test Framework Basics

JerseyTest is developed by Jersey themselves in order to facilitate the testing of their rest services.
You can really easily test your services against a set of preconfigured containers or even an external container. In this guide, we’ll focus on a preconfigured container, namely jetty.
This guide covers,
  1. Jersey Test Framework Overview
  2. Jersey Test Framework Basics
  3. Supported Containers
  4. Running TestNG Tests
  5. Easy steps to write test using Jersey Test Framework

1. Jersey Test Framework Overview

Jersey Test Framework originated as an internal tool used for verifying the correct implementation of server-side components. Testing RESTful applications became a more pressing issue with "modern" approaches like test-driven development and users started to look for a tool that could help with designing and running the tests as fast as possible but with many options related to test execution environment.
The current implementation 2.27 of Jersey Test Framework supports the following set of features:
  • pre-configured client to access deployed application
  • support for multiple containers - grizzly, in-memory, jdk, simple, jetty
  • able to run against any external container
  • automated configurable traffic logging
Jersey Test Framework is primarily based on JUnit but you can run tests using TestNG as well. It works almost out-of-the-box and it is easy to integrate it within your Maven-based project. While it is usable on all environments where you can run JUnit, we support primarily the Maven-based setups.

2. Jersey Test Framework Basics

If you want to develop a test using Jersey Test Framework, you need to subclass JerseyTest and configure the set of resources and/or providers that will be deployed as part of the test application.
The below short code snippet shows basic resource class UserResource used in tests defined as part of the UserResourceTest class. The overridden configure method returns a ResourceConfig of the test application, that contains only the UserResource resource class. ResourceConfig is a sub-class of JAX-RS Application. It is a Jersey convenience class for configuring JAX-RS applications. ResourceConfig also implements JAX-RS Configurable interface to make the application configuration more flexible. 
Create Jersey Rest API and it's corresponding JUnit test case.
Example: Create Jersey Rest API.
@Path("/users")
public class UserResource {

 private UserService userService = new UserService();

 @GET
 @Produces(MediaType.APPLICATION_JSON)
 public List<User> fetchAll() {
  return userService.fetchAll();
 }
 
 @GET
 @Path("user/{id}")
 @Produces(MediaType.APPLICATION_JSON)
 public Response getById(@PathParam("id") int id) {
  return Response.ok().entity(new User(100, "me", "[email protected]")).build();
 }
}
Let's develop a test using Jersey Test Framework to above Resource class - UserRespurce.java.
Test cases using Jersey Test Framework
public class UserResourceTest extends JerseyTest {

 @Override
 public Application configure() {
  enable(TestProperties.LOG_TRAFFIC);
  enable(TestProperties.DUMP_ENTITY);
  return new ResourceConfig(UserResource.class);
 }

 @Test
 public void tesFetchAll() {
  Response response = target("/users").request().get();
  assertEquals("should return status 200", 200, response.getStatus());
  assertNotNull("Should return user list", response.getEntity().toString());
  System.out.println(response.getStatus());
  System.out.println(response.readEntity(String.class));
 }

 @Test
 public void testGetById() {
  Response output = target("/users/user/100").request().get();
  assertEquals("Should return status 200", 200, output.getStatus());
  assertNotNull("Should return user object as json", output.getEntity());
  System.out.println(output.getStatus());
  System.out.println(output.readEntity(String.class));
 }
}

3. Supported Containers

JerseyTest supports deploying applications on various containers, all (except the external container wrapper) need to have some "glue" code to be supported. Currently, Jersey Test Framework provides support for Grizzly, In-Memory, JDK (com.sun.net.httpserver.HttpServer), Simple HTTP container (org.simpleframework.http) and Jetty HTTP container (org.eclipse.jetty).
Following is a brief description of all container factories supported in Jersey Test Framework.
  • Jersey provides 2 different test container factories based on Grizzly. The GrizzlyTestContainerFactory creates a container that can run as a light-weight, plain HTTP container. Almost all Jersey tests are using Grizzly HTTP test container factory. The second factory is GrizzlyWebTestContainerFactory that is Servlet-based and supports Servlet deployment context for tested applications. This factory can be useful when testing more complex Servlet-based application deployments.
<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.27</version>
</dependency>
  • The in-memory container is not a real container. It starts Jersey application and directly calls internal APIs to handle request created by client provided by test framework. There is no network communication involved. This container does not support servlet and other container dependent features, but it is a perfect choice for simple unit tests.
<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-inmemory</artifactId>
    <version>2.27</version>
</dependency>
  • HttpServer from Oracle JDK is another supported test container.
<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-jdk-http</artifactId>
    <version>2.27</version>
</dependency>
  • Simple container (org.simpleframework.http) is another light-weight HTTP container that integrates with Jersey and is supported by Jersey Test Framework.
<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-simple</artifactId>
    <version>2.27</version>
</dependency>
  • Jetty container (org.eclipse.jetty) is another high-performance, light-weight HTTP server that integrates with Jersey and is supported by Jersey Test Framework.
<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-jetty</artifactId>
    <version>2.27</version>
</dependency>

4. Running TestNG Tests

It is possible to run not only JUnit tests but also tests based on TestNG. Add TestNG to your class-patch, i.e.:
<dependency>
    <groupId>org.glassfish.jersey.test-framework</groupId>
    <artifactId>jersey-test-framework-core</artifactId>
    <version>2.27</version>
</dependency>
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>...</version>
</dependency>
With JerseyTestNg, you can start one instance of test container for all tests present in a test class or separate test container for each and every test. For this reason, separate subclasses of JerseyTestNg have been created:
JerseyTestNg.ContainerPerClassTest creates one container to run all the tests in. Setup method is annotated with @BeforeClassteardown method with @AfterClass.
For example take a look at ContainerPerClassTest test. It contains two test methods (first and second), one singleton resource that returns an increasing sequence of number. Example:
public class ContainerPerClassTest extends JerseyTestNg.ContainerPerClassTest {
 
    @Path("/")
    @Singleton
    @Produces("text/plain")
    public static class Resource {
 
        private int i = 1;
 
        @GET
        public int get() {
            return i++;
        }
    }
 
    @Override
    protected Application configure() {
        return new ResourceConfig(Resource.class);
    }
 
    @Test(priority = 1)
    public void first() throws Exception {
        test(1);
    }
 
    @Test(priority = 2)
    public void second() throws Exception {
        test(2);
    }
 
    private void test(final Integer expected) {
        final Response response = target().request().get();
 
        assertEquals(response.getStatus(), 200);
        assertEquals(response.readEntity(Integer.class), expected);
    }
}
JerseyTestNg.ContainerPerMethodTest creates a separate container for each test. Setup method is annotated with @BeforeMethodteardown method with @AfterMethod.
We can create a similar test to the previous one. Take a look at ContainerPerMethodTest test. It looks the same except the expected values and extending class: it contains two test methods (first and second), one singleton resource that returns an increasing sequence of number. Example:
public class ContainerPerMethodTest extends JerseyTestNg.ContainerPerMethodTest {
 
    @Path("/")
    @Singleton
    @Produces("text/plain")
    public static class Resource {
 
        private int i = 1;
 
        @GET
        public int get() {
            return i++;
        }
    }
 
    @Override
    protected Application configure() {
        return new ResourceConfig(Resource.class);
    }
 
    @Test
    public void first() throws Exception {
        test(1);
    }
 
    @Test
    public void second() throws Exception {
        test(1);
    }
 
    private void test(final Integer expected) {
        final Response response = target().request().get();
 
        assertEquals(response.getStatus(), 200);
        assertEquals(response.readEntity(Integer.class), expected);
    }
}

5. Steps to writing test using Jersey Test Framework

1. Add dependencies to pom.xml(If you are using maven project). Add Jetty container and JUnit maven dependencies to pom.xml.
<!-- testing -->
        <dependency>
            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
            <artifactId>jersey-test-framework-provider-jetty</artifactId>
            <version>${jersey.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
2. Create Test class named UserResourceTest and extends JerseyTest under test package.
public class UserResourceTest extends JerseyTest {
}
3. Configure and register resource classes
public class UserResourceTest extends JerseyTest {

 @Override
 public Application configure() {
  enable(TestProperties.LOG_TRAFFIC);
  enable(TestProperties.DUMP_ENTITY);
  return new ResourceConfig(UserResource.class);
 }
}
4. Write a test for each sub-resources or rest apis.
@Test
public void tesFetchAll() {
 Response response = target("/users").request().get();
 assertEquals("should return status 200", 200, response.getStatus());
 assertNotNull("Should return user list", response.getEntity().toString());
 System.out.println(response.getStatus());
 System.out.println(response.readEntity(String.class));
}

@Test
public void testGetById() {
 Response output = target("/users/user/100").request().get();
 assertEquals("Should return status 200", 200, output.getStatus());
 assertNotNull("Should return user object as json", output.getEntity());
 System.out.println(output.getStatus());
 System.out.println(output.readEntity(String.class));
}
5. Running test
  1. Using maven through the command line
mvn test -Dtest=classname
  1. From eclipse, right click and run as JUnit Test
6. Print output to console.
Jun 14, 2018 11:20:02 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
log4j:WARN No appenders could be found for logger (org.eclipse.jetty.util.log).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
200
[{"email":"[email protected]","id":100,"name":"A"},{"email":"[email protected]","id":101,"name":"B"},{"email":"[email protected]","id":102,"name":"C"}]
Jun 14, 2018 11:20:04 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
200
{"email":"[email protected]","id":100,"name":"me"}

Conclusion

This post explained basics of Jersey Test Framework.
Learn more about Jersey Rest framework on Jersey Rest Developer Guide.
All the code of this post is available over on Github. This is a Maven-based project, so it should be easy to import and run as it is.

Comments