Por que TDD em Rust não é chato, mas sim vantajoso?
\n\nVocê já escreveu um código que funcionava "mais ou menos certo" e depois encontrou um bug no lugar mais inesperado? Conhecido. Desenvolvimento Orientado a Testes (TDD) é um método que vira o processo habitual de cabeça para baixo. Em vez de primeiro escrever o código e depois adivinhar se funciona, você primeiro escreve um teste que deve falhar e, em seguida, escreve exatamente a quantidade de código necessária para o teste passar.
\n\nRust é uma linguagem que já no nível do compilador protege você de toda uma classe de erros (adeus segfaults e condições de corrida!). Mas mesmo o compilador não garante que sua lógica esteja correta. TDD em Rust adiciona a essa segurança mais uma camada: você não apenas escreve código, mas documenta o comportamento esperado diretamente nos testes. E isso é incrivelmente legal.
\n\nNeste artigo, vamos explorar TDD em Rust com exemplos práticos. Você verá como escrever testes antes da implementação, como executá-los com cargo test e como refatorar o código sem medo de quebrar algo. Vamos lá!
O que é TDD e por que Rust é ideal para ele?
\n\nTDD significa Test-Driven Development (Desenvolvimento Orientado a Testes). O ciclo é simples e elegante:
\n\n- \n
- Vermelho — escrevemos um teste que descreve uma nova funcionalidade. Executamos — o teste falha (lógico, o código ainda não existe). \n
- Verde — escrevemos o código mínimo para o teste passar. Não pensamos em beleza, apenas em passar no teste. \n
- Refatoração — melhoramos o código sem alterar seu comportamento. Os testes permanecem verdes. \n
Rust é ideal para TDD por várias razões:
\n- \n
- Sistema de teste integrado —
cargo testfunciona pronto para uso, sem necessidade de frameworks externos. \n - Tipagem forte — o compilador detecta erros de tipo, e os testes detectam erros lógicos. Juntos, são imbatíveis. \n
- Propriedade e empréstimo — os testes ajudam a garantir que você está trabalhando corretamente com a memória, sem criar cópias desnecessárias. \n
- Comunidade e documentação — a comunidade Rust promove ativamente os testes, com muitos exemplos disponíveis. \n
Configuração do projeto para TDD
\n\nVamos criar um novo projeto:
\ncargo new tdd_rust_example\ncd tdd_rust_example\n\nPor padrão, cargo new cria um arquivo src/main.rs com um programa simples. Vamos escrever uma biblioteca, então renomeie-o para src/lib.rs (ou simplesmente exclua main.rs e crie lib.rs). Em Cargo.toml não é necessário alterar nada — os testes já estão incluídos.
A propósito, se você estiver escrevendo apenas uma biblioteca (sem um arquivo executável), use cargo new --lib.
Primeiro teste: vermelho
\n\nImagine que queremos escrever uma função que soma dois números. Pelo TDD, primeiro escrevemos o teste. Abra src/lib.rs e adicione:
#[cfg(test)]\nmod tests {\n #[test]\n fn test_add() {\n let result = add(2, 3);\n assert_eq!(result, 5);\n }\n}\n\nExecute:
\ncargo test\n\nVocê verá um erro de compilação — a função add não está definida. Isso é normal. Estamos na zona vermelha.
Verde: implementação mínima
\n\nAgora vamos escrever exatamente a quantidade de código necessária para o teste passar. Adicione a função add acima do módulo de teste:
fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n \n #[test]\n fn test_add() {\n let result = add(2, 3);\n assert_eq!(result, 5);\n }\n}\n\nObserve o use super::*; — isso importa tudo do módulo pai (nosso código) para o módulo de teste.
Execute cargo test novamente. Verde! O teste passa. Fizemos o mínimo — retornamos a soma. Parece