Testes de Integração Rust com Docker: Nível Avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Testes de Integração Rust com Docker: Nível Avançado



Testes de integração são uma etapa crítica no desenvolvimento em Rust, especialmente quando sua aplicação interage com serviços externos: bancos de dados, filas de mensagens, HTTP-API. O uso do Docker permite criar ambientes isolados e reproduzíveis para testes. Neste artigo, abordaremos técnicas avançadas: desde a configuração básica até a execução paralela de testes com testcontainers e docker-compose.



Por que Docker para testes de integração?

Mocks e stubs tradicionais muitas vezes não refletem o comportamento real das dependências. O Docker resolve esse problema:

  • Isolamento: cada teste é executado em um contêiner limpo.
  • Reprodutibilidade: mesmo ambiente em todas as máquinas dos desenvolvedores e no CI.
  • Paralelismo: é possível executar vários bancos de dados de teste simultaneamente.


1. Configuração básica: testando com PostgreSQL

Vamos começar com algo simples: testar uma função que trabalha com PostgreSQL. Usaremos a crate testcontainers — um wrapper Rust para gerenciar contêineres Docker.

Adicione as dependências no Cargo.toml:

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


Exemplo de teste:

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();

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

Importante: o contêiner é automaticamente removido após a conclusão do teste (graças à implementação Drop).



2. Configuração avançada: imagem personalizada com migrações

Frequentemente é necessário executar migrações previamente. Vamos criar uma imagem personalizada baseada em um Dockerfile:

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


No teste Rust, use 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); // ... usando instance}

Para construir a imagem no CI, use docker build -f Dockerfile.test -t my-app-test:latest .



3. Execução paralela de testes com Docker Compose

Se seu serviço requer várias dependências (PostgreSQL + Redis), use docker-compose. Crie o arquivo 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"


No teste Rust, levante o ambiente 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