Compartir comentarios
Las respuestas se generan en base a la documentación.

Escribir pruebas con Testcontainers

Quarkus Dev Services

Quarkus Dev Services aprovisiona automáticamente servicios no configurados en modo de desarrollo y prueba. Cuando incluyes una extensión y no la configuras, Quarkus inicia el servicio correspondiente utilizando Testcontainers en segundo plano y conecta la aplicación para que utilice ese servicio.

Note

Dev Services requiere un entorno Docker compatible.

Quarkus Dev Services es compatible con la mayoría de los servicios de uso común, como bases de datos SQL, Kafka, RabbitMQ, Redis y MongoDB. Para obtener más información, consulta la guía de Quarkus Dev Services (en inglés).

Escribir pruebas para los endpoints de la API

Prueba los endpoints GET /api/customers y POST /api/customers utilizando REST Assured. La biblioteca io.rest-assured:rest-assured ya se agregó como dependencia de prueba al generar el proyecto.

Crea CustomerResourceTest.java y anótalo con @QuarkusTest. Esto arranca la aplicación junto con los servicios requeridos utilizando Dev Services. Dado que no has configurado las propiedades del datasource, Dev Services inicia automáticamente una base de datos PostgreSQL utilizando Testcontainers.

package com.testcontainers.demo;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.jupiter.api.Assertions.assertFalse;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.common.mapper.TypeRef;
import io.restassured.http.ContentType;
import java.util.List;
import org.junit.jupiter.api.Test;

@QuarkusTest
class CustomerResourceTest {

    @Test
    void shouldGetAllCustomers() {
        List<Customer> customers = given().when()
                .get("/api/customers")
                .then()
                .statusCode(200)
                .extract()
                .as(new TypeRef<>() {});
        assertFalse(customers.isEmpty());
    }

    @Test
    void shouldCreateCustomerSuccessfully() {
        Customer customer = new Customer(null, "John", "[email protected]");
        given().contentType(ContentType.JSON)
                .body(customer)
                .when()
                .post("/api/customers")
                .then()
                .statusCode(201)
                .body("name", is("John"))
                .body("email", is("[email protected]"));
    }
}

Esto es lo que hace la prueba:

  • @QuarkusTest inicia la aplicación completa de Quarkus con Dev Services habilitado.
  • Dev Services inicia un contenedor PostgreSQL utilizando Testcontainers y configura el datasource automáticamente.
  • shouldGetAllCustomers() llama a GET /api/customers y verifica que se devuelvan los datos sembrados por la migración de Flyway.
  • shouldCreateCustomerSuccessfully() envía una solicitud POST /api/customers y verifica que la respuesta contenga los datos del cliente creado.

Personalizar la configuración de las pruebas

De forma predeterminada, la instancia de prueba de Quarkus se inicia en el puerto 8081 y utiliza una imagen Docker de postgres:14. Personaliza ambos agregando estas propiedades a src/main/resources/application.properties:

quarkus.http.test-port=0
quarkus.datasource.devservices.image-name=postgres:15.2-alpine

Establecer quarkus.http.test-port=0 inicia la aplicación en un puerto aleatorio disponible, evitando conflictos de puertos. La propiedad devservices.image-name te permite fijar la imagen de PostgreSQL a una versión específica que coincida con la de producción.

Probar con servicios no compatibles con Dev Services

Es posible que tu aplicación utilice un servicio que Dev Services no admita de forma nativa. En ese caso, utiliza QuarkusTestResourceLifecycleManager para iniciar el servicio antes de que la aplicación Quarkus comience a ejecutarse para las pruebas.

Por ejemplo, supón que la aplicación utiliza CockroachDB. Primero, agrega la dependencia del módulo CockroachDB de Testcontainers:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>cockroachdb</artifactId>
    <scope>test</scope>
</dependency>

Crea un CockroachDBTestResource que implemente QuarkusTestResourceLifecycleManager:

package com.testcontainers.demo;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import java.util.HashMap;
import java.util.Map;
import org.testcontainers.containers.CockroachContainer;

public class CockroachDBTestResource implements QuarkusTestResourceLifecycleManager {

    CockroachContainer cockroachdb;

    @Override
    public Map<String, String> start() {
        cockroachdb = new CockroachContainer("cockroachdb/cockroach:v22.2.0");
        cockroachdb.start();
        Map<String, String> conf = new HashMap<>();
        conf.put("quarkus.datasource.jdbc.url", cockroachdb.getJdbcUrl());
        conf.put("quarkus.datasource.username", cockroachdb.getUsername());
        conf.put("quarkus.datasource.password", cockroachdb.getPassword());
        return conf;
    }

    @Override
    public void stop() {
        cockroachdb.stop();
    }
}

Utiliza el CockroachDBTestResource con @QuarkusTestResource en una clase de prueba:

package com.testcontainers.demo;

import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertFalse;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.common.mapper.TypeRef;
import java.util.List;
import org.junit.jupiter.api.Test;

@QuarkusTest
@QuarkusTestResource(value = CockroachDBTestResource.class, restrictToAnnotatedClass = true)
class CockroachDBTest {

    @Test
    void shouldGetAllCustomers() {
        List<Customer> customers = given().when()
                .get("/api/customers")
                .then()
                .statusCode(200)
                .extract()
                .as(new TypeRef<>() {});
        assertFalse(customers.isEmpty());
    }
}

El atributo restrictToAnnotatedClass = true garantiza que el contenedor de CockroachDB solo se inicie cuando se ejecute esta clase de prueba específica, en lugar de activarse para todas las pruebas.