Ir al contenido principal
Versión: 6.1

Testcontainers

[Traducción Beta No Oficial]

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Testcontainers

nota

Esta documentación es para la última versión del módulo Testcontainers y es compatible con Kotest 6.0+.

El proyecto Testcontainers proporciona instancias ligeras y efímeras de bases de datos comunes, Elasticsearch, Kafka, Redis o cualquier otro servicio que pueda ejecutarse en un contenedor Docker, ideales para usar en pruebas.

Kotest ofrece integración con Testcontainers mediante un módulo adicional que proporciona soporte para:

  • Contenedores GenericContainer

  • Contenedores ComposeContainer

  • Bases de datos compatibles con JDBC

Dependencias

Para comenzar, añade la siguiente dependencia en tu archivo de compilación Gradle.

io.kotest:kotest-extensions-testcontainers:${kotest.version}

Para Maven, necesitarás estas dependencias:


<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-extensions-testcontainers</artifactId>
<version>${kotest.version}</version>
<scope>test</scope>
</dependency>
nota

Desde Kotest 6.0, todas las extensiones se publican bajo el grupo io.kotest con una cadencia de versiones vinculada a las principales versiones de Kotest.

Contenedores genéricos

Kotest ofrece dos extensiones de GenericContainer: TestContainerSpecExtension y TestContainerProjectExtension, que pueden usarse para encapsular cualquier contenedor y vincular su ciclo de vida al de la especificación (spec) o proyecto, según la extensión utilizada.

Podemos crear la extensión usando un contenedor fuertemente tipado o un nombre de imagen de Docker.

Usando un contenedor fuertemente tipado:

val elasticsearch = install(ContainerExtension(ElasticsearchContainer(ELASTICSEARCH_IMAGE))) {
withPassword(ELASTICSEARCH_PASSWORD)
}

O usando un nombre de imagen de Docker:

val container = install(TestContainerSpecExtension(GenericContainer("redis:5.0.3-alpine"))) {
startupAttempts = 2
withExposedPorts(6379)
}
val jedis = JedisPool(container.host, container.firstMappedPort)

Se prefiere el contenedor fuertemente tipado cuando está disponible en el proyecto Testcontainers, ya que brinda acceso a configuraciones específicas, como la opción password en el ejemplo de Elasticsearch anterior. Sin embargo, cuando no existe un contenedor fuertemente tipado, el primer método permite recurrir a cualquier imagen de Docker como contenedor genérico.

Una vez instalado el contenedor, puedes usar su host y puerto para configurar un cliente que acceda a él. Por ejemplo, para conectar un cliente Jedis a un contenedor Redis:

val container = install(TestContainerSpecExtension(GenericContainer("redis:5.0.3-alpine")))
val jedis = JedisPool(container.host, container.firstMappedPort)
consejo

Usa TestContainerProjectExtension si deseas compartir el mismo contenedor entre múltiples especificaciones (specs) en un proyecto para reducir los tiempos de inicio.

Bases de datos

Para bases de datos compatibles con JDBC, Kotest ofrece JdbcDatabaseContainerSpecExtension y JdbcDatabaseContainerProjectExtension. Estas no devuelven el contenedor directamente, sino un javax.sql.DataSource, respaldado por una instancia de HikariCP, que puede configurarse durante la inicialización.

Primero, crea el contenedor.

val mysql = MySQLContainer<Nothing>("mysql:8.0.26").apply {
startupAttempts = 1
withUrlParam("connectionTimeZone", "Z")
withUrlParam("zeroDateTimeBehavior", "convertToNull")
}

Segundo, instala el contenedor dentro de una extensión, proporcionando un lambda opcional de configuración para Hikari.

val ds = install(JdbcDatabaseContainerSpecExtension(mysql)) {
// these are hikari pool config options
poolName = "myconnectionpool"
maximumPoolSize = 8
idleTimeout = 10000
}

Si no deseas configurar el pool, puedes omitir el lambda final. Si prefieres no usar Hikari, puedes usar las extensiones genéricas en su lugar.

Luego el datasource puede usarse en una prueba. Por ejemplo, aquí tienes un ejemplo completo de inserción de objetos y su posterior recuperación para verificar que la inserción fue exitosa.

class QueryDatastoreTest : FunSpec({

val mysql = MySQLContainer<Nothing>("mysql:8.0.26").apply {
startupAttempts = 1
withUrlParam("connectionTimeZone", "Z")
withUrlParam("zeroDateTimeBehavior", "convertToNull")
}

val ds = install(JdbcDatabaseContainerSpecExtension(mysql)) {
poolName = "myconnectionpool"
maximumPoolSize = 8
idleTimeout = 10000
}

val datastore = PersonDatastore(ds)

test("insert happy path") {

datastore.insert(Person("sam", "Chicago"))
datastore.insert(Person("jim", "Seattle"))

datastore.findAll().shouldBe(
listOf(
Person("sam", "Chicago"),
Person("jim", "Seattle"),
)
)
}
})
consejo

Usa JdbcDatabaseContainerProjectExtension si deseas compartir el mismo contenedor entre múltiples especificaciones (specs) en un proyecto para reducir los tiempos de inicio.

Contenedores Compose

Kotest ofrece dos extensiones para contenedores ComposeContainer: ComposeContainerSpecExtension y ComposeContainerProjectExtension. Esta extensión puede usarse para encapsular ComposeContainer e iniciar múltiples contenedores simultáneamente definidos en un archivo docker compose.

Podemos crear la extensión usando un File que apunte al archivo docker compose:

val container = install(ComposeContainerSpecExtension(ComposeContainer(File("my-compose-file.yml"))))

Alternativamente, si nuestro archivo docker compose está en la carpeta de recursos del proyecto, podemos usar este acceso directo:

// eg for src/main/resources/docker-compose.yml
val container = install(ComposeContainerSpecExtension.fromResource("docker-compose.yml"))

Registros de contenedores

Kotest ofrece la opción de capturar los registros de los contenedores iniciados por las extensiones y mostrarlos en la consola de pruebas. Esto puede habilitarse pasando una instancia de ContainerExtensionConfig a la extensión. En la instancia de configuración, establece la opción logConsumer como StandardLogConsumer, especificando el nivel de registros a capturar. Por ejemplo:

install(
TestContainerSpecExtension(
container,
ContainerExtensionConfig(logConsumer = StandardLogConsumer(LogTypes.ALL))
)
)

Los tipos de registro se pueden configurar para capturar ALL, STDOUT, STDERR o NONE.