Por que a cobertura de código não é apenas uma marca no CI/CD?
\n\nImagine: você escreveu em Rust um módulo para analisar arquivos de configuração complexos. O compilador está feliz, os testes passam, mas um mês depois a produção falha com um erro em um caso extremo raro. Familiar? É aqui que entra a cobertura de código com testes em Rust — uma métrica que mostra qual porcentagem do seu código é realmente executada durante os testes.
\n\nMas sejamos honestos: a busca por 100% de cobertura é uma armadilha. É muito mais importante entender quais linhas ficaram sem testes e por quê. Neste artigo, vamos analisar as três principais ferramentas para Rust: tarpaulin, grcov e o conjunto de ferramentas LLVM integrado. Você aprenderá como transformar porcentagens secas em insights acionáveis para refatoração.
Por que um desenvolvedor Rust deve monitorar a cobertura?
\nRust é conhecido por sua segurança de memória, mas isso não elimina erros lógicos. A cobertura de código com testes ajuda a:
\n- \n
- Detectar "código morto" — funções ou ramificações que nunca são chamadas. \n
- Aumentar a confiança durante a refatoração — sabendo que os caminhos críticos estão cobertos por testes. \n
- Melhorar a documentação — os testes geralmente servem como a melhor documentação se cobrirem todos os cenários. \n
A métrica principal é a line coverage (cobertura de linhas), mas também veremos a branch coverage (cobertura de ramificações), que em Rust é especialmente importante devido à abundância de expressões match.
\n\nFerramenta nº 1: cargo-tarpaulin — simplicidade e velocidade
\ntarpaulin é a ferramenta mais popular para cobertura de código em Rust. Funciona "pronto para uso" e não requer configuração complexa. Instalação:
cargo install cargo-tarpaulin\nExecutando a análise básica:
\ncargo tarpaulin --out Html\nEste comando gera um relatório HTML na pasta tarpaulin-report.html. Ao abri-lo, vemos um mapa de cores do seu projeto: linhas verdes (cobertas por testes), vermelhas (não cobertas) e cinzas (não executáveis, como comentários).
Exemplo: testando uma função simples
\nCrie um arquivo src/lib.rs com uma função de cálculo de fatorial:
pub fn factorial(n: u32) -> u32 {\n match n {\n 0 | 1 => 1,\n _ => n * factorial(n - 1),\n }\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_factorial() {\n assert_eq!(factorial(0), 1);\n assert_eq!(factorial(1), 1);\n assert_eq!(factorial(5), 120);\n }\n}\nExecute o tarpaulin:
\ncargo tarpaulin --ignore-tests --out Html\nA flag --ignore-tests exclui o código dos testes do relatório. Resultado: 100% de cobertura para esta função. Mas vamos complicar — adicione tratamento de erros:
pub fn factorial_safe(n: i32) -> Result<u32, String> {\n if n < 0 {\n return Err("Número negativo!".to_string());\n }\n Ok(factorial(n as u32))\n}\nAgora o tarpaulin mostrará que a ramificação Err não está coberta por testes. Adicione um teste:
#[test]\nfn test_negative() {\n assert!(factorial_safe(-5).is_err());\n}\nApós executar novamente, a cobertura volta a ser 100%.
\n\nConfigurações avançadas do tarpaulin
\nPara projetos grandes, use:
\n- \n
--fail-under 80— saída com erro se a cobertura for inferior a 80%. \n --skip-clean— não reconstruir o projeto se as alterações forem insignificantes. \n --engine llvm— usar o conjunto de ferramentas LLVM (experimental, mas mais preciso). \n
Ferramenta nº 2: grcov — o rei das integrações
\ngrcov é uma ferramenta mais flexível que trabalha com o conjunto de ferramentas LLVM. É especialmente útil se você usa CI/CD (GitHub Actions, GitLab