proptest para Rust: guia completo de property-based testing
1. O que é e para que serve
A biblioteca proptest é um poderoso framework para property-based testing (testes baseados em propriedades) na linguagem Rust. Diferente dos testes unitários tradicionais, onde você define manualmente dados de entrada específicos e o resultado esperado, o property-based testing propõe descrever propriedades (invariantes) que devem ser verdadeiras para quaisquer dados de entrada válidos. Em seguida, a biblioteca gera automaticamente uma grande quantidade de casos de teste aleatórios e verifica se a propriedade especificada é violada.
Por que isso é importante? Primeiro, permite encontrar "casos de borda" (edge cases) que o desenvolvedor nem imaginava: strings vazias, números negativos, valores muito grandes, estados nulos. Segundo, os testes baseados em propriedades são autodocumentáveis: eles descrevem o contrato da função ("para qualquer número x, a função f(x) retorna um número maior que 0"), e não um exemplo específico. Terceiro, ao modificar o código, esses testes geralmente continuam funcionando sem alterações, pois verificam propriedades gerais, não valores concretos.
proptest é o equivalente das bibliotecas QuickCheck (Haskell), Hypothesis (Python) e FsCheck (.NET). Ela oferece um rico conjunto de estratégias de geração de dados (de números simples a estruturas complexas), um mecanismo de redução (shrinkage) para minimizar exemplos de falha e integração com o framework de testes principal do Rust — cargo test.
2. Instalação
Para usar o proptest, adicione-o na seção [dev-dependencies] do seu arquivo Cargo.toml:
[dev-dependencies]
proptest = "1.4"
Em seguida, execute o comando:
cargo build
A biblioteca será baixada e compilada. Agora você pode usá-la nos seus módulos de teste.
3. Início rápido — exemplo mínimo funcional
Vamos escrever um teste simples que verifica se a função reverse (inverter string) é uma involução: se aplicada duas vezes, obtemos a string original.
// src/lib.rs
pub fn reverse(s: &str) -> String {
s.chars().rev().collect()
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn test_reverse_involution(s in ".*") {
let reversed = reverse(&s);
let double_reversed = reverse(&reversed);
assert_eq!(s, double_reversed);
}
}
}
Execute o teste com o comando cargo test. O proptest gerará 256 strings aleatórias (valor padrão) e verificará se a propriedade é válida. Se o teste falhar, a biblioteca tentará encontrar o menor exemplo que reproduza o erro.
4. Métodos e funções principais
Abaixo estão os principais componentes da biblioteca proptest. Todos os exemplos assumem que use proptest::prelude::*; foi adicionado no início do módulo de teste.
4.1. Macro proptest!
Assinatura: proptest! { ... }
O que faz: Macro principal que define um bloco de testes baseados em propriedades. Dentro dele, você pode declarar funções de teste com geração automática de dados.
proptest! {
#[test]
fn test_addition_commutative(a in 0..100i32, b in 0..100i32) {
assert_eq!(a + b, b + a);
}
}
4.2. Estratégia any::<T>()
Também na biblioteca
Trabalhando com Markdown em Node.js: bibliotecas e ferramentas para conversão
Monitoramento de aplicações TypeScript: ferramentas e bibliotecas
Sinon para JavaScript (Node.js): guia completo com exemplos práticos
Internacionalização (i18n) em Go (Golang): Guia Completo