Por que testes E2E em Rust não são um luxo, mas uma necessidade
\n\nVocê já iniciou uma aplicação Rust em produção e, uma hora depois, recebeu pânico dos usuários? "Tudo funciona perfeitamente na minha máquina!" — frase familiar? O problema é que os testes unitários verificam apenas partes isoladas do código, e os testes de integração verificam a interação entre componentes. Mas o verdadeiro inferno começa quando todo o pipeline, desde a requisição HTTP até o banco de dados, falha devido a uma combinação não óbvia.
\n\nTestes E2E de aplicações Rust (End-to-End) são a única maneira de garantir que sua API, utilitário CLI ou serviço web funcionem como um todo coeso. Neste artigo, não vamos apenas falar sobre teoria, mas escrever testes reais que podem ser imediatamente implementados em CI/CD. Sem enrolação — apenas Rust e uma abordagem pronta para produção.
\n\nO que são testes E2E no contexto do Rust?
\n\nAo contrário dos testes unitários (que testam funções) e dos testes de integração (que testam módulos), os testes end-to-end Rust verificam o ciclo completo de funcionamento da aplicação: da entrada à saída. Para um serviço web, isso se parece com:
\n\n- \n
- Iniciar um servidor real (ou sua imagem Docker). \n
- Enviar uma requisição HTTP através de um cliente (por exemplo,
reqwest). \n - Verificar a resposta: status, corpo, cabeçalhos. \n
- Validar o estado do banco de dados (se houver). \n
Para aplicações CLI — é executar o binário com argumentos e verificar stdout/stderr. Para aplicações desktop — simular ações do usuário através do WebDriver (Selenium).
\n\nQuando os testes E2E são obrigatórios?
\n- \n
- Você está desenvolvendo uma API pública. \n
- Você tem uma arquitetura de microsserviços. \n
- A aplicação interage com serviços externos (bancos de dados, filas, S3). \n
- Você deseja evitar regressões a cada commit. \n
Ferramentas para testes E2E em Rust
\n\nO ecossistema Rust é rico, mas para E2E precisamos apenas de algumas bibliotecas-chave:
\n\n| Biblioteca | Finalidade |
|---|---|
reqwest | Cliente HTTP para enviar requisições ao servidor em teste. |
tokio | Runtime assíncrono — base para executar testes e o servidor. |
wiremock | Servidor Mock para simular APIs externas. |
assert_cmd + predicates | Para testar aplicações CLI. |
fantoccini | Cliente WebDriver (se precisar testar o navegador). |
Usaremos o Rust testing framework nativo (módulo test), mas adicionaremos assincronicidade através de tokio::test.
Prática: Escrevendo testes E2E para um serviço web em Actix-Web
\n\nSuponha que temos uma aplicação web Rust simples em Actix-Web com o endpoint /api/users, que retorna uma lista de usuários do PostgreSQL. Queremos garantir que, em execução real, tudo funcione.
Passo 1: Preparação do ambiente de teste
\n\nCriaremos um arquivo separado tests/e2e.rs (o Rust automaticamente trata arquivos na pasta tests/ como testes de integração).
// tests/e2e.rs\nuse std::process::{Command, Stdio};\nuse std::time::Duration;\nuse tokio::time::sleep;\n\n// Função auxiliar: inicia o servidor em segundo plano\nasync fn start_server() -> std::process::Child {\n let child = Command::new("cargo")\n .args(&["run", "--bin", "my_app"])\n .stdout(Stdio::null())\n .stderr(Stdio::null())\n .spawn()\n .expect("Falha ao iniciar o servidor");\n\n // Dá tempo ao servidor para iniciar\n sleep(Duration::from_secs(5)).await;\n child\n}\n\nImportante: Em um projeto real, use Docker ou uma configuração de banco de dados separada para testes, para não poluir a produção.
\n\n