Noções Básicas de Testes
10 exemplos para você começar com Testes - 7 básicos e 3 intermediários.
Pré-requisitos
- Rust 1.97.0 (edição 2024)
- Familiaridade com
cargo testde Noções Básicas de Cargo
Exemplos Básicos
1. Seu Primeiro Teste de Unidade
Testes são funções anotadas com #[test] no mesmo módulo ou em um módulo tests/.
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adds_positive() {
assert_eq!(add(2, 2), 4);
}
}#[cfg(test)]compila testes apenas paracargo testassert_eq!imprime o lado esquerdo/direito em caso de falha- Testes rodam em paralelo por padrão
cargo test adds_positivefiltra por nome
Relacionado: Testes de Unidade vs. Integração - posicionamento de testes
2. assert!, assert_eq!, assert_ne!
Rust fornece macros para verificações booleanas e de igualdade.
#[test]
fn validates_email() {
let email = "user@example.com";
assert!(email.contains('@'));
assert_ne!(email, "");
assert_eq!(email.split('@').count(), 2);
}assert!falha em condições falsasassert_eq!usaPartialEqe mostra a diferença- Adicione mensagens personalizadas:
assert!(x > 0, "x era {x}") - Prefira nomes de teste descritivos em vez de strings de mensagem
3. should_panic
Verifique se o código entra em pânico (panic) com entrada inválida.
#[test]
#[should_panic(expected = "divide by zero")]
fn panics_on_zero() {
let _ = 1 / 0;
}- Use com moderação; prefira
Resultem código de biblioteca expected(substring) deve corresponder à carga útil do pânico#[should_panic]semexpectedcorresponde a qualquer pânico- Documente por que o pânico é o contrato correto
4. Result em Testes
Retorne Result de testes para usar ? para falhas de configuração.
#[test]
fn reads_config() -> std::io::Result<()> {
let data = std::fs::read_to_string("Cargo.toml")?;
assert!(data.contains("[package]"));
Ok(())
}Errfalha o teste comoassert!- Mais limpo do que
unwrapaninhado na configuração - Funciona bem com
?em análise e helpers de I/O - Ainda use
assert!para expectativas comportamentais
5. Executando Subconjuntos
Cargo filtra testes por substring de nome.
cargo test
cargo test add_
cargo test --lib
cargo test --test integration_orders--libexecuta apenas testes de unidade emsrc/--test NOMEexecuta um arquivo de teste de integração-- --nocapturemostra a saída deprintln!-- --test-threads=1para testes que compartilham estado global
6. Módulos de Teste e Visibilidade
Teste funções privadas do mesmo crate.
mod parser {
fn parse_id(s: &str) -> Option<u64> {
s.parse().ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_digits() {
assert_eq!(parse_id("42"), Some(42));
}
}
}- Testes de unidade vivem em
mod testsao lado do código use super::*importa itens privados- Testes de integração veem apenas a API
pub - Mantenha os testes próximos ao código que eles exercitam
7. Ignorando Testes e Testes Caros
Pule testes lentos por padrão; execute explicitamente em CI nightly.
#[test]
fn fast_case() {
assert_eq!(2 + 2, 4);
}
#[test]
#[ignore]
fn heavy_simulation() {
// long-running
}cargo test -- --ignored#[ignore]exclui o teste docargo testpadrão- CI pode executar testes ignorados em agendamento
- Prefira flags de feature em vez de
ignorepara dependências opcionais - Documente por que um teste é ignorado em um comentário
Exemplos Intermediários
8. Harness de Teste Personalizado (lib test)
Bibliotecas podem personalizar a descoberta de testes (avançado).
// src/lib.rs
pub fn init() {}
#[cfg(test)]
mod tests {
#[test]
fn smoke() {
super::init();
}
}- O harness padrão é suficiente para a maioria dos crates
- Harnesses personalizados são raros; use testes de integração primeiro
- Veja atributos instáveis do crate
testapenas quando necessário
Relacionado: Organização de Testes - configuração compartilhada
9. Testando com Dependências de Desenvolvimento
Adicione crates apenas para testes sem enviá-los aos consumidores.
[dev-dependencies]
tempfile = "3"
pretty_assertions = "1"#[test]
fn writes_temp_file() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("out.txt");
std::fs::write(&path, b"ok").unwrap();
assert!(path.exists());
}dev-dependenciesnão são transitivas- Use
pretty_assertions::assert_eqpara diffs mais claros tempfileevita poluir o repositório com artefatos de teste
Relacionado: Mocking e Test Doubles - fakes e mocks
10. Próximos Passos: Testes de Propriedade e Snapshot
Combine testes de unidade com garantias mais fortes.
#[test]
fn reverse_twice_is_identity() {
let v = vec![1, 2, 3];
let mut w = v.clone();
w.reverse();
w.reverse();
assert_eq!(v, w);
}- Testes de propriedade generalizam muitas entradas (Testes Baseados em Propriedade)
- Testes de snapshot travam a saída formatada (Testes de Snapshot)
- Testes assíncronos precisam de
#[tokio::test](Testando Código Assíncrono)
Relacionado: Melhores Práticas de Teste - padrões de equipe
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.