<h2>Fundamentos de Testes em Rust</h2>
<p>Testes em Rust são nativos à linguagem e totalmente integrados ao ecossistema via <strong>Cargo</strong>, o gerenciador de pacotes. Diferentemente de outras linguagens, você não precisa instalar frameworks externos para começar. A stdlib de Rust fornece tudo necessário através do atributo <code>#[test]</code> e da função <code>assert!()</code> e variações.</p>
<p>O Cargo oferece dois tipos principais: <strong>testes unitários</strong> (escritos dentro dos módulos que testam) e <strong>testes de integração</strong> (em arquivos separados, testando a API pública). Executar testes é tão simples quanto <code>cargo test</code>. Rust compila testes como binários especiais e os executa em paralelo por padrão, tornando o feedback extremamente rápido mesmo em projetos maiores.</p>
<h2>Testes Unitários: Estrutura Básica</h2>
<h3>Escrevendo seu primeiro teste unitário</h3>
<p>Testes unitários vivem no mesmo arquivo do código que testam. Use o atributo <code>#[cfg(test)]</code> para organizar um módulo de testes que só compila quando você executa <code>cargo test</code>. Aqui está um exemplo real:</p>
<pre><code class="language-rust">// src/lib.rs
pub fn adicionar(a: i32, b: i32) -> i32 {
a + b
}
pub fn dividir(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Divisão por zero".to_string())
} else {
Ok(a / b)
}
}
#[cfg(test)]
mod testes {
use super::*;
#[test]
fn teste_adicionar_positivos() {
assert_eq!(adicionar(2, 3), 5);
}
#[test]
fn teste_adicionar_negativos() {
assert_eq!(adicionar(-1, -1), -2);
}
#[test]
fn teste_divisao_sucesso() {
assert_eq!(dividir(10, 2).unwrap(), 5);
}
#[test]
fn teste_divisao_por_zero() {
assert!(dividir(10, 0).is_err());
}
#[test]
#[should_panic(expected = "Divisão por zero")]
fn teste_divisao_panic() {
if let Err(e) = dividir(10, 0) {
panic!("{}", e);
}
}
}</code></pre>
<p>A macro <code>assert_eq!()</code> compara valores, <code>assert!()</code> valida booleanos, e <code>#[should_panic]</code> verifica se o código falha corretamente. Use <code>unwrap()</code> e <code>is_err()</code> para trabalhar com <code>Result</code> em testes. Execute <code>cargo test</code> e você verá cada teste executado individualmente com feedback colorido.</p>
<h3>Truques úteis</h3>
<p>Use <code>#[ignore]</code> para pular testes durante desenvolvimento: <code>#[test] #[ignore]</code>. Execute apenas testes ignorados com <code>cargo test -- --ignored</code>. Para rodar um teste específico: <code>cargo test nome_do_teste</code>. Use <code>cargo test -- --nocapture</code> para ver saídas <code>println!</code> durante testes.</p>
<h2>Testes de Integração</h2>
<h3>Estrutura e organização</h3>
<p>Testes de integração testam sua biblioteca como um usuário externo faria. Eles ficam em um diretório especial <code>tests/</code> na raiz do projeto. Cada arquivo <code>.rs</code> dentro de <code>tests/</code> é compilado como um crate binário separado. Isso garante que você teste apenas a API pública.</p>
<p>Crie a estrutura: seu <code>Cargo.toml</code> fica em <code>/</code>, <code>src/lib.rs</code> em <code>/src</code>, e testes de integração em <code>/tests/*.rs</code>. Diferentemente de testes unitários, você não usa <code>#[cfg(test)]</code> nem módulos privados. Importe sua lib normalmente:</p>
<pre><code class="language-rust">// tests/integracao.rs
use seu_projeto::adicionar;
use seu_projeto::dividir;
#[test]
fn teste_fluxo_completo_adicionar() {
let resultado = adicionar(5, 5);
assert_eq!(resultado, 10);
}
#[test]
fn teste_fluxo_divisao_com_validacao() {
match dividir(20, 4) {
Ok(res) => assert_eq!(res, 5),
Err(_) => panic!("Divisão falhou inesperadamente"),
}
}
#[test]
fn teste_integracao_multiplas_operacoes() {
let soma = adicionar(10, 20);
let resultado = dividir(soma, 5).expect("Divisão falhou");
assert_eq!(resultado, 6);
}</code></pre>
<p>Execute <code>cargo test --test integracao</code> para rodar apenas esse arquivo de testes. Se você tiver múltiplos arquivos em <code>tests/</code>, cada um é executado independentemente. Isso é poderoso para testar cenários complexos que envolvem múltiplas funções públicas trabalhando juntas.</p>
<h2>Cargo test: Controle Total</h2>
<h3>Executando e filtrando testes</h3>
<p>O comando <code>cargo test</code> é extremamente flexível. Execute <code>cargo test -- --help</code> para ver todas as opções. Alguns comandos práticos:</p>
<ul>
<li><code>cargo test</code> — executa todos os testes (unitários e integração)</li>
<li><code>cargo test --lib</code> — apenas testes unitários</li>
<li><code>cargo test --test *</code> — apenas testes de integração</li>
<li><code>cargo test adicionar</code> — filtra por nome (roda <code>teste_adicionar_positivos</code>, etc.)</li>
<li><code>cargo test -- --test-threads=1</code> — executa serialmente (útil para debugging)</li>
<li><code>cargo test -- --nocapture</code> — mostra <code>println!</code> mesmo em testes passando</li>
<li><code>cargo test -- --show-output</code> — alias moderno do acima</li>
</ul>
<p>Use <code>cargo test --release</code> para compilar otimizado (mais lento na compilação, mais rápido na execução). Perfeito para suites grandes ou testes de performance.</p>
<h3>Boas práticas com Cargo</h3>
<p>Organize seus testes de integração em subdiretórios lógicos dentro de <code>tests/</code>. Por exemplo: <code>tests/operacoes/</code> e <code>tests/validacoes/</code> com um <code>mod.rs</code> em cada. Isso mantém a estrutura clara conforme sua suite cresce. Lembre-se: código em <code>tests/</code> é compilado como crates independentes, então cada arquivo precisa ser autocompleto.</p>
<h2>Conclusão</h2>
<p>Aprendemos três pilares fundamentais: <strong>(1) testes unitários usam <code>#[cfg(test)]</code> no mesmo arquivo, oferecendo isolamento e velocidade</strong>; <strong>(2) testes de integração ficam em <code>tests/</code> e testam a API pública como um usuário externo faria</strong>; <strong>(3) <code>cargo test</code> oferece controle fino sobre execução — filtros, paralelização, output — tudo integrado</strong>. Combine essas três práticas com disciplina e você terá confiança máxima no seu código Rust.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch11-00-testing.html" target="_blank" rel="noopener noreferrer">The Rust Programming Language - Testing</a></li>
<li><a href="https://doc.rust-lang.org/cargo/commands/cargo-test.html" target="_blank" rel="noopener noreferrer">Cargo - Tests</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/testing.html" target="_blank" rel="noopener noreferrer">Rust by Example - Testing</a></li>
<li><a href="https://www.oreilly.com/library/view/effective-rust/9781098105891/" target="_blank" rel="noopener noreferrer">Effective Rust - Item 3: Testing</a></li>
<li><a href="https://doc.rust-lang.org/book/ch11-03-test-organization.html" target="_blank" rel="noopener noreferrer">Test Organization - Rust Official Documentation</a></li>
</ul>