Pruebas de Integración de Rust con Docker: Nivel Avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Pruebas de Integración de Rust con Docker: Nivel Avanzado



Las pruebas de integración son una etapa críticamente importante en el desarrollo con Rust, especialmente cuando tu aplicación interactúa con servicios externos: bases de datos, colas de mensajes, HTTP-API. El uso de Docker permite crear entornos aislados y reproducibles para las pruebas. En este artículo, exploraremos técnicas avanzadas: desde la configuración básica hasta la ejecución paralela de pruebas con testcontainers y docker-compose.



¿Por qué Docker para pruebas de integración?

Los mocks y stubs tradicionales a menudo no reflejan el comportamiento real de las dependencias. Docker resuelve este problema:

  • Aislamiento: cada prueba se ejecuta en un contenedor limpio.
  • Reproducibilidad: el mismo entorno en todas las máquinas de los desarrolladores y en CI.
  • Paralelismo: se pueden ejecutar múltiples bases de datos de prueba simultáneamente.


1. Configuración básica: pruebas con PostgreSQL

Empecemos con algo simple: probemos una función que trabaja con PostgreSQL. Usamos el crate testcontainers — un wrapper de Rust para gestionar contenedores Docker.

Agregue las dependencias en Cargo.toml:

[dev-dependencies]testcontainers = "0.18"tokio = { version = "1", features = ["full"] }sqlx = { version = "0.8", features = ["runtime-tokio", "postgres"] }


Ejemplo de prueba:

use sqlx::PgPool;use testcontainers::clients::Cli;use testcontainers::images::postgres::Postgres;

#[tokio::test]async fn test_database_connection() { let docker = Cli::default(); let postgres_instance = docker.run(Postgres::default()); let connection_string = &format!( "postgres://postgres:postgres@127.0.0.1:{}/postgres", postgres_instance.get_host_port_ipv4(5432) );

let pool = PgPool::connect(connection_string).await.unwrap();

// Ejecutamos la consulta SQL let row: (i32,) = sqlx::query_as("SELECT 1 + 1") .fetch_one(&pool) .await .unwrap(); assert_eq!(row.0, 2);}

Importante: el contenedor se elimina automáticamente después de que finaliza la prueba (gracias a la implementación de Drop).



2. Configuración avanzada: imagen personalizada con migraciones

A menudo es necesario ejecutar migraciones previamente. Creemos una imagen personalizada basada en un Dockerfile:

# Dockerfile.testFROM postgres:16-alpineCOPY migrations/ /docker-entrypoint-initdb.d/


En la prueba de Rust usamos Image:

use testcontainers::images::generic::GenericImage;

#[tokio::test]async fn test_with_migrations() { let docker = Cli::default(); let image = GenericImage::new("my-app-test:latest") .with_wait_for(testcontainers::core::WaitFor::message_on_stdout( "database system is ready to accept connections" )); let instance = docker.run(image); // ... usamos instance}

Para construir la imagen en CI se puede usar docker build -f Dockerfile.test -t my-app-test:latest .



3. Ejecución paralela de pruebas con Docker Compose

Si tu servicio requiere múltiples dependencias (PostgreSQL + Redis), usa docker-compose. Cree un archivo docker-compose.test.yml:

version: '3.8'services:  postgres:    image: postgres:16-alpine    environment:      POSTGRES_PASSWORD: testpass    ports:      - "5432"  redis:    image: redis:7-alpine    ports:      - "6379"


En la prueba de Rust levantamos el entorno de Compose:

use testcontainers::clients::Cli;use testcontainers::images::compose::Compose;

#[tokio::test]async fn test_with_compose() { let docker = Cli::default(); let compose = Compose::new("docker-compose.test.y

Blogs

Book Recommendations