How to test Jersey Rest API with JUnit

1. Overview

In this guide, you will learn how to test Jersey Rest API with JUnit.
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.
Technology and tools used: 
  • Maven 3 
  • JDK 8
  •  Jersey 2.27
  •  Apache Tomcat 8.5 
  • Eclipse Neon

2. Create Maven Web Application Project

You can create a quick start Java web application project by using the Maven maven-archetype-webapp template. In a terminal (*unix or Mac) or command prompt (Windows), navigate to the folder you want to create the project.
Type this command :
$ mvn archetype:generate -DgroupId={project-packaging} 
 -DartifactId={project-name} 
 -DarchetypeArtifactId=maven-archetype-webapp 
 -DinteractiveMode=false

//for example 
$ mvn archetype:generate -DgroupId=com.ramesh
 -DartifactId=jersey-junit-test-example
 -DarchetypeArtifactId=maven-archetype-webapp 
 -DinteractiveMode=false

3. Update Jersey, Test Dependencies in a Pom.Xml File

Let's configure jersey, junit and jetty. We use the maven-war-plugin to tell Maven not to fail over the missing web.xml file. Because we don’t need it for this application.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.javadevelopersguide.jersey</groupId>
  <artifactId>jersey-junit-test-example</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>jersey-junit-test-example Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
  <dependencies>
  <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.1.0</version>
   <scope>provided</scope>
  </dependency>

  <dependency>
   <groupId>org.glassfish.jersey.core</groupId>
   <artifactId>jersey-server</artifactId>
   <version>${jersey.version}</version>
  </dependency>
  <dependency>
   <groupId>org.glassfish.jersey.containers</groupId>
   <artifactId>jersey-container-servlet</artifactId>
   <version>${jersey.version}</version>
  </dependency>

  <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-moxy -->
  <dependency>
   <groupId>org.glassfish.jersey.media</groupId>
   <artifactId>jersey-media-moxy</artifactId>
   <version>${jersey.version}</version>
  </dependency>

  <dependency>
   <groupId>org.glassfish.jersey.inject</groupId>
   <artifactId>jersey-hk2</artifactId>
   <version>${jersey.version}</version>
  </dependency>

  <!-- Required only when you are using JAX-RS Client -->
  <dependency>
   <groupId>org.glassfish.jersey.core</groupId>
   <artifactId>jersey-client</artifactId>
   <version>${jersey.version}</version>
  </dependency>

  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>1.7.21</version>
  </dependency>
  
  <!-- 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>
 </dependencies>

 <build>
  <finalName>jersey-junit-test-example</finalName>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
     <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
   </plugin>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0.2</version>
    <configuration>
     <source>1.8</source>
     <target>1.8</target>
    </configuration>
   </plugin>
   <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
   </plugin>
  </plugins>
 </build>

 <properties>
  <jersey.version>2.26</jersey.version>
  <junit.version>4.12</junit.version>
 </properties>
  
</project>

4. Develop Jersey Rest Service - UserResource.java

This jersey rest service is a simple example to explain the common HTTP Methods used like: GET, POST, PUT, DELETE. So I can properly show you how to unit test these services.
package com.javadevelopersguide.jersey.resources;

import java.util.ArrayList;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import com.javadevelopersguide.jersey.model.User;

@Path("/users")
public class UserResource {

 @GET
 @Produces(MediaType.APPLICATION_JSON)
 public List<User> fetchAll() {
   List<User> users = new ArrayList<User>();
  users.add(new User(100, "A", "demo@gmail.com"));
  users.add(new User(101, "B", "demo1@gmail.com"));
  users.add(new User(102, "C", "demo2@gmail.com"));
  return users;
 }
 
 @GET
 @Path("user/{id}")
 @Produces(MediaType.APPLICATION_JSON)
 public Response getById(@PathParam("id") int id) {
  return Response.ok().entity(new User(100, "me", "me@gmail.com")).build();
 }
 
 @POST
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
 public Response create(User user) {
  // Add user logic here
  return Response.status(Status.CREATED).build();
 }

 
 @PUT
 @Path("/user/{id}")
 @Consumes(MediaType.APPLICATION_JSON)
 public Response update(@PathParam("id") long id, User user) {
  // update user logic here
  return Response.noContent().build();
 }

 @DELETE
 @Path("/user/{id}")
 public Response delete(@PathParam("id") long id) {
  // Delete user logic here
  return Response.status(Status.NO_CONTENT).entity("User deleted successfully !!").build();
 }
}

5. User Model Class - User.java

User (Data Transfer Object) used for automatic marshaling and data retrieval. In this example, we have used moxy media for JSON support.
package com.javadevelopersguide.jersey.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {
 private long id;
 private String name;
 private String email;
 
 public User() {
  
 }
 
 
 public User(long id, String name, String email) {
  super();
  this.id = id;
  this.name = name;
  this.email = email;
 }
 public long getId() {
  return id;
 }
 public void setId(long id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}

6. Jersey application Configuration

This configures jersey so we don’t need a web.xml file.
package com.javadevelopersguide.jersey.config;

import java.util.logging.Level;

import java.util.logging.Logger;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("resources")
public class AppResourceConfig extends ResourceConfig {
 public AppResourceConfig() {
  packages("com.javadevelopersguide.jersey.resources");
  register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
    Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
 }
}

7. Test Jersey Rest Service with JUnit and Jersey

Testing with jersey Test Framework is relatively easy. You need to subclass org.glassfish.jersey.test.JerseyTest and configure the resource and/or providers that need to be deployed in order to test our services. We need to override the JerseyTest#configure() method to configure our application. In this example, we return a ResourceConfig. The ### ResourceConfig is a sub-class of JAX-RS Application. It is a Jersey convenience class for configuring JAX-RS applications.
Finally, we can write our JUnit tests. We obtain a WebTarget by calling the JerseyTest#target(path) method. It is on this target we can make a request, add parameters, headers, etc.. When the WebTarget is invoked we simply investigate the response namely the status code returned by the service.
package com.javadevelopersguide.jersey.resources;

import static junit.framework.TestCase.assertNotNull;
import static org.junit.Assert.assertEquals;

import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.Test;

import com.javadevelopersguide.jersey.model.User;

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));
 }

 @Test
 public void testCreate() {
  User user = new User(105, "Ramesh", "myemail@gmail.com");
  Response output = target("/users").request().post(Entity.entity(user, MediaType.APPLICATION_JSON));
  System.out.println(output.getStatus());
  assertEquals("Should return status 201", 201, output.getStatus());
 }

 @Test
 public void testUpdate() {
  User user = new User(105, "Ramesh", "myemail@gmail.com");
  Response output = target("/users/user/101").request().put(Entity.entity(user, MediaType.APPLICATION_JSON));
  assertEquals("Should return status 204", 204, output.getStatus());
  System.out.println(output.getStatus());
 }

 @Test
 public void testDelete() {
  Response output = target("/users/user/100").request().delete();
  assertEquals("Should return status 204", 204, output.getStatus());
 }
}

8. Running Tests

  1. Using maven through the command line
mvn test -Dtest=classname
  1. From eclipse, right click and run as JUnit Test
Print output to console:
Jun 14, 2018 11:42:43 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":"demo@gmail.com","id":100,"name":"A"},{"email":"demo1@gmail.com","id":101,"name":"B"},{"email":"demo2@gmail.com","id":102,"name":"C"}]
Jun 14, 2018 11:42:45 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
200
{"email":"me@gmail.com","id":100,"name":"me"}
Jun 14, 2018 11:42:45 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
201
Jun 14, 2018 11:42:45 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
Jun 14, 2018 11:42:46 AM org.glassfish.jersey.test.jetty.JettyTestContainerFactory$JettyTestContainer <init>
INFO: Creating JettyTestContainer configured at the base URI http://localhost:9998/
204

9. Conclusion

This guide illustrated how to test Jersey Rest API with JUnit.
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