Explorando el marco de pruebas de Jersey

1. Información general

En este tutorial, vamos a echar un vistazo a Jersey Test Framework y veremos cómo podemos usarlo para escribir rápidamente pruebas de integración.

Como ya hemos visto en artículos anteriores, Jersey es un marco de código abierto para desarrollar servicios web RESTful . Podemos obtener más información sobre Jersey en nuestra introducción a la creación de una API con el artículo de Jersey y Spring, aquí.

2. Configuración de la aplicación

Jersey Test Framework es una herramienta que nos ayuda a verificar la correcta implementación de nuestros componentes del lado del servidor. Como veremos más adelante, proporciona una forma rápida y sencilla de escribir pruebas de integración y puede manejar muy bien la comunicación con nuestras API HTTP.

Asimismo, funciona casi de forma inmediata y es fácil de integrar con nuestros proyectos basados ​​en Maven . El marco se basa principalmente en JUnit, aunque también es posible usarlo con TestNG, lo que lo hace utilizable en casi todos los entornos.

En la siguiente sección, veremos qué dependencias necesitamos agregar a nuestra aplicación para usar el marco.

2.1. Dependencias de Maven

En primer lugar, agreguemos la dependencia principal de Jersey Test Framework a nuestro pom.xml :

 org.glassfish.jersey.test-framework jersey-test-framework-core 2.27 test 

Como siempre, podemos obtener la última versión de Maven Central.

Casi todas las pruebas de Jersey utilizan la fábrica de contenedores de prueba Grizzly de facto, que también necesitaremos agregar:

 org.glassfish.jersey.test-framework.providers jersey-test-framework-provider-grizzly2 2.27 test 

Nuevamente podemos encontrar la última versión en Maven Central.

3. Introducción

En la siguiente sección, cubriremos los pasos básicos necesarios para escribir una prueba simple.

Comenzaremos probando el recurso simple de saludos en nuestro servidor:

@Path("/greetings") public class Greetings { @GET @Path("/hi") public String getHiGreeting() { return "hi"; } } 

3.1. Configurar la prueba

Ahora definamos nuestra clase de prueba:

public class GreetingsResourceIntegrationTest extends JerseyTest { @Override protected Application configure() { return new ResourceConfig(Greetings.class); } //... } 

Podemos ver en el ejemplo anterior que para desarrollar una prueba usando Jersey Test Framework, nuestra prueba necesita subclase JerseyTest .

A continuación, anulamos el método de configuración que devuelve una configuración de recurso personalizada para nuestra prueba y solo contiene el recurso Greetings . Este es, por supuesto, el recurso que deseamos probar.

3.2. Escribiendo nuestra primera prueba

Comencemos probando una simple solicitud GET de nuestra API de saludos:

@Test public void givenGetHiGreeting_whenCorrectRequest_thenResponseIsOkAndContainsHi() { Response response = target("/greetings/hi").request() .get(); assertEquals("Http Response should be 200: ", Status.OK.getStatusCode(), response.getStatus()); assertEquals("Http Content-Type should be: ", MediaType.TEXT_HTML, response.getHeaderString(HttpHeaders.CONTENT_TYPE)); String content = response.readEntity(String.class); assertEquals("Content of ressponse is: ", "hi", content); } 

Observe que tenemos acceso completo a la respuesta HTTP, por lo que podemos hacer cosas como verificar el código de estado para asegurarnos de que la operación fue realmente exitosa o trabajar con el cuerpo real de la respuesta .

Expliquemos con más detalle lo que hacemos en el ejemplo anterior:

  1. Envíe una solicitud HTTP GET a '/ greetings / hi'
  2. Verifique el código de estado HTTP y los encabezados de respuesta del tipo de contenido
  3. Pruebe el contenido de la respuesta que contiene la cadena "hola"

4. Prueba de GET para recuperar recursos

Ahora que hemos visto los pasos básicos involucrados en la creación de pruebas. Probemos la API de Fruit simple que presentamos en el excelente artículo de soporte de Jersey MVC.

4.1. Obtenga JSON simple

En el siguiente ejemplo, estamos trabajando con el cuerpo de la respuesta como una cadena JSON estándar:

@Test public void givenFruitExists_whenSearching_thenResponseContainsFruit() { final String json = target("fruit/search/strawberry").request() .get(String.class); assertThat(json, containsString("{\"name\":\"strawberry\",\"weight\":20}")); }

4.2. Obtener entidad en lugar de JSON

También podemos mapear la respuesta directamente a una clase de entidad de recurso, por ejemplo:

 @Test public void givenFruitExists_whenSearching_thenResponseContainsFruitEntity() { final Fruit entity = target("fruit/search/strawberry").request() .get(Fruit.class); assertEquals("Fruit name: ", "strawberry", entity.getName()); assertEquals("Fruit weight: ", Integer.valueOf(20), entity.getWeight()); }

Esta vez, especificamos el tipo de Java al que se convertirá la entidad de respuesta en el método get : un objeto Fruit .

5. Prueba de POST para crear recursos

Para crear un nuevo recurso en nuestra API, haremos un buen uso de las solicitudes POST. En la siguiente sección, veremos cómo probar esta parte de nuestra API.

5.1. Publicar JSON simple

Comencemos publicando una cadena JSON simple para probar la creación de un nuevo recurso de frutas:

@Test public void givenCreateFruit_whenJsonIsCorrect_thenResponseCodeIsCreated() { Response response = target("fruit/created").request() .post(Entity.json("{\"name\":\"strawberry\",\"weight\":20}")); assertEquals("Http Response should be 201 ", Status.CREATED.getStatusCode(), response.getStatus()); assertThat(response.readEntity(String.class), containsString("Fruit saved : Fruit [name: strawberry colour: null]")); }

En el ejemplo anterior, usamos el método post que toma un parámetro de objeto Entity . Usamos el conveniente método json para crear una entidad a partir de la cadena JSON correspondiente .

5.2. Post Entity Instead of JSON

As we've already seen with get requests we can also post a Resource entity class directly – for example:

@Test public void givenCreateFruit_whenFruitIsInvalid_thenResponseCodeIsBadRequest() { Fruit fruit = new Fruit("Blueberry", "purple"); fruit.setWeight(1); Response response = target("fruit/create").request(MediaType.APPLICATION_JSON_TYPE) .post(Entity.entity(fruit, MediaType.APPLICATION_JSON_TYPE)); assertEquals("Http Response should be 400 ", 400, response.getStatus()); assertThat(response.readEntity(String.class), containsString("Fruit weight must be 10 or greater")); }

This time we use the entity method to post our Fruit entity and also specify the media type as JSON.

5.3. Form Submissions Using POST

In our final post example we will see how to test form submissions via a post request:

@Test public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() { Form form = new Form(); form.param("name", "apple"); form.param("colour", null); Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED) .post(Entity.form(form)); assertEquals("Http Response should be 400 ", 400, response.getStatus()); assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null")); }

Similarly, we make use of the Entity class but this time pass a form which contains a number of parameters to our post request.

6. Testing Other HTTP Verbs

Sometimes we need to test other HTTP endpoints such as PUT and DELETE. This is of course perfectly possible using the Jersey Test Framework.

Let's see a simple PUT example:

@Test public void givenUpdateFruit_whenFormContainsBadSerialParam_thenResponseCodeIsBadRequest() { Form form = new Form(); form.param("serial", "2345-2345"); Response response = target("fruit/update").request(MediaType.APPLICATION_FORM_URLENCODED) .put(Entity.form(form)); assertEquals("Http Response should be 400 ", 400, response.getStatus()); assertThat(response.readEntity(String.class), containsString("Fruit serial number is not valid")); }

Once we have called the request method, we can invoke any HTTP method on the current request object.

7. Additional Features

The Jersey test framework contains a number of additional configuration properties which can help aid debugging and testing.

In the next example we'll see how to programmatically enable a feature with a given name:

public class FruitResourceIntegrationTest extends JerseyTest { @Override protected Application configure() { enable(TestProperties.LOG_TRAFFIC); enable(TestProperties.DUMP_ENTITY); //...

When we create and configure our Jersey application under test. We can also enable additional properties. In this case, we enable two logging properties – LOG_TRAFFIC and DUMP_ENTITYwhich will provide useful additional logging and debug information during test runs.

8. Supported Containers

As we've already mentioned the defacto container used when writing tests with the Jersey Test Framework is Grizzly. However, a number of other containers are supported:

  • In-Memory container
  • HttpServer from Oracle JDK
  • Simple container (org.simpleframework.http
  • Jetty container (org.eclipse.jetty)

For more information on how to configure these containers, please see the documentation here.

9. Conclusion

To summarize, in this tutorial, we’ve explored the Jersey Test Framework. First, we started by introducing how to configure the Jersey Test Framework and then we saw how to write a test for a very simple API.

In the next section, we saw how to write tests for a variety of GET and POST API endpoints. Finally, we looked at some additional features and the containers that the Jersey Test Framework supports.

Como siempre, el código fuente completo del artículo está disponible en GitHub.