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.
NoteDev 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:
@QuarkusTestinicia 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 aGET /api/customersy verifica que se devuelvan los datos sembrados por la migración de Flyway.shouldCreateCustomerSuccessfully()envía una solicitudPOST /api/customersy 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-alpineEstablecer 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.