Prueba tus API REST con Rest Assured

En este tutorial vamos a ver cómo probar de manera muy sencilla el funcionamiento de cualquier API REST que se nos ponga por delante

Prueba tus API REST con Rest Assured

Indice de contenidos

  1. Introducción
  2. Entorno
  3. Nuestra primera prueba con Rest Assured
  4. Guardando el cuerpo de la respuesta
  5. Mostrar el contenido de request y response
  6. Conclusiones
  7. Referencias

1. Introducción

De un tiempo a esta parte, es cada vez más común que las aplicaciones expongan su funcionalidad mediante API REST, que pueda ser consumida por aplicaciones JavaScript, aplicaciones móviles, etc.

Y, al igual que usamos herramientas como Concordion y Selenium para asegurar que la funcionalidad que ofrece nuestra aplicación web es correcta, lo mismo debemos hacer con nuestros API. La ventaja es que para probar estas piezas disponemos desde hace tiempo de un buen conjunto de herramientas que nos permiten comprobar la funcionalidad que exponemos (HttpClient para hacer las invocaciones, Jackson para manipular JSON, etc.). Pero son utilidades pensadas para realizar peticiones y no expresamente para probar.

Hoy vamos a conocer Rest Assured una herramienta pensada específicamente para probar llamadas a API REST y, en general, cualquier pertición que se ejecute sobre el protocolo HTTP.

2. Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: Portatil MacBook Pro 17′ (2.8GHz Intel Core i7, 8GB DDR3)
  • Sistema operativo: MacOS Sierra 10.12.3
  • Entorno de desarrollo: IntelliJ IDEA 2017.1
  • JDK 1.8
  • Rest Assured 3.0.2

3. Nuestra primera prueba con Rest Assured

Para hacer nuestras pruebas, he decidido utilizar un API REST ya existente, concretamente “swapi”, que maneja información del universo de Star Wars. Podéis encontrar este API y su documentación en swapi.co

A continuación os pego el contenido del test, y posteriormente comentamos los aspectos más curiosos

Lo primero que observamos es que la forma de describir la prueba con Rest Assured sigue el formato Gherkin (Given – When – Then), casi un estándar de la definición de escenarios de prueba.

Además, vemos también que podemos configurar para las peticiones tanto la URI a la que atacarán como los parámetros que se van a enviar en el “query string”. También podríamos, si quisiéramos, añadirle un cuerpo, subir un fichero con una petición “multipart”… Lo que se os ocurra. También podemos configurar el nivel de log que queremos para la response (volcar toda la petición, sólo las cabeceras, o el cuerpo, o…), y lo mismo podríamos hacer con la request. Esta es la salida que se mostraría en este caso, en que hemos solicitado que se vuelque la información de la respuesta

En este caso, se trata de una petición usando el verbo GET pero, evidentemente, el framework soporta peticiones usando prácticamente todos los verbos HTTP (soporta GET, POST, PUT, PATCH, DELETE, HEAD y OPTIONS). Y además, una vez realizada la petición, el mismo framework nos posibilita realizar aserciones sobre el contenido de la respuesta, usando los “matchers” de Hamcrest, que aportan bastante legibilidad a las pruebas, encargándose él de parsear la información, lo que nos facilita bastante la vida.

También es posible extraer el cuerpo de la respuesta si necesitamos hacer validaciones más complejas o si queremos guardarlo para usar algún elemento en futuras peticiones. En este ejemplo lo hemos almacenado en un String, pero podemos usar el objeto que queramos, incluso uno creado por nosotros (En el peor de los casos, será necesario crear un mapper específico

para nuestro objeto, pero seguirá siendo posible)

Para demostrar lo dicho en los párrafos anteriores, y más cosas interesantes de Rest Assured, vamos a seguir jugando con el framework…

4. Guardando el cuerpo de la respuesta

En el siguiente ejemplo, vamos a modificar el test anterior para guardar el cuerpo de la respuesta en un objeto propio, y posteriormente usarlo para invocar a otro endpoint

Al ejecutar el test salta un error… RestAssured indica que no tiene ningún parser de JSON en el classpath, así que hay que añadir a mi pom.xml la dependencia de Jackson Databind

Si ahora ejecutamos de nuevo, todo va como la seda 🙂

5. Mostrar el contenido de request y response

Hemos visto también que es posible volcar al log el contenido de la request y la response. En las pruebas que hemos visto hasta ahora, lo hemos hecho añadiendo las llamadas al método “log()”, que nos permite configurar el nivel de detalle (de request y response por separado). Puedo indicar que se trace sólo el cuerpo (“log().body()”), el cuerpo y las cabeceras (“log().body().and().log().headers()”).

Pero existen otras formas de activar el vocado al log. Imaginemos que no nos interesa tener el detalle cuando todo va bien, pero que sí queremos que nos muestre la información de request/response en caso de que las validaciones solicitadas fallen. Para ver cómo hacer esto, vamos a simplificar un poco nuestro test

Podemos ver que, en la parte del “given” se ha añadido un nuevo elemento, “config()”, en le que hemos indicado que queremos habilitar las trazas sólo cuando fallen las validaciones. De esta manera, si se ejecuta el test tal cual está no mostrará traza, pero si se cambia el “statusCode” de 200 (success) a 404 (not found) y volvemos a ejecutar sí veremos el detalle completo de la request y la response.

Pero ¿qué pasa si en mi test hago varias llamadas y quiero el mismo comportamiento para cada una de ellas? ¿Tengo que configurar el log en cada petición que cree? La respuesta es “no”… RestAssured permite habilitar cierta configuración de manera global en lugar de hacerlo en la propia petición. Por ejemplo:

Si ejecutamos este test, no sacará traza para la primera llamada, pues se ejecuta correctamente, pero sí para la segunda, puesto que la aserción del statusCode fallará.

Sin embargo, no todo es bonito en el mundo del logging de Rest Assured… Por defecto, las trazas las vuelca directamente a la consola y no hay forma de decirle directamente que las vuelque en un sistema de traza estilo Log4J o similares. Sin embargo, existen formas de burlar esta limitación… Lo que sí permite el framework es indicar un PrintStream al que volcar las trazas de la prueba, y los PrintStream reciben como parámetro un OutputStream. Así que lo que vamos a hacer es implementarnos nuestro propio OutputStream, y decirle que imprima lo que reciba en el logger que le indiquemos:

Y ahora modificamos el código de la prueba para que emplee nuestro OutputStream

Con esto ya tendríamos la prueba mandando las trazas a nuestro logger. Aunque el constructor del objeto PrintStream nos permite indicarle que debe hacer “flush” automáticamente, en este caso es mejor no hacerlo y encargarnos nosotros de hacerlo a mano. Si activáramos el “autoflush” la traza de nuestra request (o response) quedaría muy “desligada”, y perderíamos legibilidad en la misma

6. Conclusiones

Cuando desarrollamos un nuevo software, las pruebas son una parte imprescindible del mismo. Son nuestra red de seguridad para asegurar que las cosas funcionan como deben y al igual que para el código de producción, es importante conocer y usar frameworks que nos permitan desarrollar las pruebas de una manera rápida y sencilla (y sin necesidad de reinventar la rueda). Además, puesto que las pruebas nos dicen qué hace nuestra aplicación, es importante también usar herramientas que ayuden a hacer el código de las mismas lo más legible posible

Rest Assured es una herramienta que nos proporciona todas estas características. Implementar una llamada es un proceso rápido y sencillo, igual que validar la respuesta obtenida. Además, el API que ofrece permite una verbosidad que hace que el código de la prueba se pueda leer casi como si fuera lenguaje natural, facilitando mucho la comprensión de lo que se está probando, lo que lo convierte en un framework a tener muy en cuenta.

7. Referencias