Cómo Probar Servicios REST en Java Usando REST-assured

Cómo Probar Servicios REST en JAVA Usando REST-assured

Capturando y Validando Datos de Respuesta de REST APIs

En este tutorial, discutiremos cómo probar servicios REST usando REST-assured, con un enfoque en capturar y validar los datos de respuesta de nuestras APIs REST. A medida que avanzamos, proporcionaremos ejemplos prácticos y consejos útiles para que puedas integrar estas pruebas en tus proyectos de JAVA.

1. Overview

Las pruebas de servicios REST son una parte crucial del desarrollo de aplicaciones modernas. Permiten verificar que los endpoints funcionan según lo esperado y garantizan que las aplicaciones se comporten correctamente ante diferentes solicitudes. REST-assured es una biblioteca popular en el ecosistema de JAVA que simplifica este proceso al proporcionar una sintaxis fácil de usar para realizar pruebas y validar respuestas de API.

2. Setup para la Clase de Prueba

En tutoriales anteriores, hemos explorado REST-assured en general y hemos mostrado cómo manipular encabezados, cookies y parámetros en las solicitudes.

Para este tutorial, hemos agregado un controlador REST simple, AppController, que llama internamente a un servicio, AppService. Utilizaremos estas clases en nuestros ejemplos de prueba.

Creando la Clase de Prueba

Empezaremos creando el esqueleto de nuestra clase de prueba, AppControllerIntegrationTest. Teniendo spring-boot-starter-test en nuestra ruta de clase, podemos aprovechar fácilmente las utilidades de prueba de Spring. Aquí tienes el código:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AppControllerIntegrationTest {

    @LocalServerPort
    private int port;

    private String uri;

    @PostConstruct
    public void init() {
        uri = "http://localhost:" + port;
    }

    @MockBean
    AppService appService;

    //test cases
}

En esta prueba de JUnit, anotamos nuestra clase con algunas anotaciones específicas de Spring que permiten inicializar la aplicación localmente en un puerto aleatorio. En @PostConstruct, capturamos la URI completa en la que realizaremos las llamadas REST. También usamos @MockBean en AppService, ya que necesitamos simular las llamadas a los métodos de esta clase.

3. Validando la Respuesta JSON

JSON es el formato más común utilizado en las APIs REST para intercambiar datos. Las respuestas pueden consistir en un solo objeto JSON o un arreglo de objetos JSON. Veremos ambos casos en esta sección.

3.1. Objeto JSON Único

Supongamos que necesitamos probar el endpoint /movie/{id}, que devuelve un objeto JSON Movie si se encuentra el id. Mockearíamos las llamadas a AppService para devolver algunos datos simulados usando el framework Mockito:

@Test
public void givenMovieId_whenMakingGetRequestToMovieEndpoint_thenReturnMovie() {

    Movie testMovie = new Movie(1, "movie1", "summary1");
    when(appService.findMovie(1)).thenReturn(testMovie);

    get(uri + "/movie/" + testMovie.getId()).then()
      .assertThat()
      .statusCode(HttpStatus.OK.value())
      .body("id", equalTo(testMovie.getId()))
      .body("name", equalTo(testMovie.getName()))
      .body("synopsis", notNullValue());
}

Aquí, primero simulamos la llamada appService.findMovie(1) para que devuelva un objeto. Luego, construimos nuestra URL REST en el método get() proporcionado por REST-assured para realizar solicitudes GET. Por último, realizamos cuatro afirmaciones: verificamos el código de estado de la respuesta y los elementos del body. Estamos utilizando Hamcrest para afirmar el valor esperado.

Si la respuesta JSON es anidada, podemos probar una clave anidada usando el operador punticoma como “key1.key2.key3”.

3.2. Extrayendo la Respuesta JSON Después de la Validación

En algunos casos, es posible que necesitemos extraer la respuesta después de la validación, para realizar operaciones adicionales sobre ella. Podemos extraer la respuesta JSON a una clase, usando el método extract():

Movie result = get(uri + "/movie/" + testMovie.getId()).then()
  .assertThat()
  .statusCode(HttpStatus.OK.value())
  .extract()
  .as(Movie.class);
assertThat(result).isEqualTo(testMovie);

En este ejemplo, dirigimos a REST-assured a extraer la respuesta JSON a un objeto Movie y luego afirmamos sobre el objeto extraído. También podemos extraer toda la respuesta a un String, usando la API extract().asString():

String responseString = get(uri + "/movie/" + testMovie.getId()).then()
  .assertThat()
  .statusCode(HttpStatus.OK.value())
  .extract()
  .asString();
assertThat(responseString).isNotEmpty();

Por último, podemos extraer un campo particular del JSON de respuesta también. Veamos un test para un API POST que espera un cuerpo JSON de Movie y devolverá el mismo objeto si se inserta correctamente:

@Test
public void givenMovie_whenMakingPostRequestToMovieEndpoint_thenCorrect() {
    Map<String, String> request = new HashMap<>();
    request.put("id", "11");
    request.put("name", "movie1");
    request.put("synopsis", "summary1");

    int movieId = given().contentType("application/json")
      .body(request)
      .when()
      .post(uri + "/movie")
      .then()
      .assertThat()
      .statusCode(HttpStatus.CREATED.value())
      .extract()
      .path("id");
    assertThat(movieId).isEqualTo(11);
}

Aquí, comenzamos creando el objeto de solicitud que necesitamos POSTear. Luego extraemos el campo id de la respuesta JSON devuelta usando el método path().

3.3. Arreglo JSON

También podemos verificar la respuesta si es un arreglo JSON:

@Test
public void whenCallingMoviesEndpoint_thenReturnAllMovies() {

Set<Movie> movieSet = new HashSet<>();
movieSet.add(new Movie(1, "movie1", "summary1"));
movieSet.add(new Movie(2, "movie2", "summary2"));
when(appService.getAll()).thenReturn(movieSet);

get(uri + "/movies").then()
    .statusCode(HttpStatus.OK.value())
    .assertThat()
    .body("size()", is(2));
}

Nuevamente, primero simulamos el appService.getAll() con algunos datos y hacemos una solicitud a nuestro endpoint. Luego afirmamos el statusCode y el size de nuestra respuesta de array.

Esto se puede hacer también a través de la extracción:

Movie[] movies = get(uri + "/movies").then()
  .statusCode(200)
  .extract()
  .as(Movie[].class);
assertThat(movies.length).isEqualTo(2);

4. Validando Encabezados y Cookies

Podemos verificar un encabezado o cookie de la respuesta utilizando métodos con el mismo nombre:

@Test
public void whenCallingWelcomeEndpoint_thenCorrect() {
    get(uri + "/welcome").then()
        .assertThat()
        .header("sessionId", notNullValue())
        .cookie("token", notNullValue());
}

También podemos extraer los encabezados y cookies individualmente:

Response response = get(uri + "/welcome");

String headerName = response.getHeader("sessionId");
String cookieValue = response.getCookie("token");
assertThat(headerName).isNotBlank();
assertThat(cookieValue).isNotBlank();

5. Validando Archivos

Si nuestra API REST devuelve un archivo, podemos usar el método asByteArray() para extraer la respuesta:

File file = new ClassPathResource("test.txt").getFile();
long fileSize = file.length();
when(appService.getFile(1)).thenReturn(file);

byte[] result = get(uri + "/download/1").asByteArray();

assertThat(result.length).isEqualTo(fileSize);

Aquí, primero simulamos appService.getFile(1) para devolver un archivo de texto que está presente en nuestro camino src/test/resources. Luego hacemos una llamada a nuestro endpoint y extraemos la respuesta en un byte[], que luego confirmamos que tenga el valor esperado.

6. Conclusión

En este tutorial, hemos explorado diferentes formas de capturar y validar respuestas de nuestras APIs REST utilizando REST-assured. Hemos visto cómo mockear respuestas, validar JSON, encabezados, cookies y hasta archivos. Con estas herramientas, puedes crear pruebas robustas que aseguren el correcto funcionamiento de tus servicios REST.

Consejos Prácticos

  • Mantén tus pruebas organizadas: Usa nombres descriptivos para tus métodos y agrúpalos lógicamente según las funciones que están probando.
  • Utiliza Mocks Efectivamente: Mockear servicios externos puede reducir la dependencia de tu código de la red y hacer que tus pruebas sean más rápidas.
  • Mantén un entorno de prueba limpio: Asegúrate de que las pruebas no afecten a tu entorno de producción, especialmente al usar datos relacionados con ellos.
  • Reutiliza código: Si tienes configuraciones comunes para tus pruebas, considera crear métodos de configuración que puedas reutilizar en múltiples clases de prueba.

Con esto, estás bien encaminado para escribir pruebas efectivas para tus servicios REST en JAVA utilizando REST-assured. ¡Empieza a probar hoy!