Tests en Rust : frameworks et outils
Rust est un langage de programmation système qui accorde une grande importance à la fiabilité et à la sécurité du code. Le système de test intégré permet aux développeurs d'écrire des tests unitaires, des tests d'intégration et des tests de documentation sans installer de bibliothèques supplémentaires. Cependant, pour des scénarios complexes — paramétrage, génération de données aléatoires ou simulation (mocking) — la communauté Rust a créé des frameworks puissants. Dans cet article, nous analyserons les outils de test clés en Rust.
Module intégré test
Rust est livré avec un module intégré test, qui est activé via l'attribut #[test]. Pour exécuter les tests, on utilise la commande cargo test. Exemple d'un test unitaire simple :
// src/lib.rspub fn add(a: i32, b: i32) -> i32 { a + b}
#[cfg(test)]mod tests { use super::*;
#[test] fn test_add() { assert_eq!(add(2, 2), 4); }
#[test] fn test_add_negative() { assert_eq!(add(-1, 1), 0); }}Fonctionnalités clés du module intégré :
- Attributs :
#[test],#[ignore],#[should_panic]. - Macros d'assertion :
assert!,assert_eq!,assert_ne!. - Tests d'intégration : placés dans le dossier
tests/et testent l'API publique. - Tests de documentation : exemples de code dans les commentaires de documentation, vérifiés via
cargo test.
Pour la plupart des projets, cela suffit. Mais lorsque la paramétrisation, la génération de données aléatoires ou le mocking sont nécessaires, des frameworks spécialisés viennent à la rescousse.
Framework rstest — tests paramétrés
La bibliothèque rstest fournit un mécanisme puissant de paramétrisation des tests, similaire à pytest en Python. Elle permet de définir plusieurs ensembles de données d'entrée et de résultats attendus sans duplication de code.
Installation :
[dev-dependencies]rstest = "0.22"Exemple de test paramétré :
use rstest::rstest;
#[rstest]#[case(1, 2, 3)]#[case(0, 0, 0)]#[case(-1, 1, 0)]fn test_add(#[case] a: i32, #[case] b: i32, #[case] expected: i32) { assert_eq!(add(a, b), expected);}Fonctionnalités de rstest :
- Paramétrisation via
#[case]. - Génération de données aléatoires via
#[random]. - Fixtures contextuelles via
#[fixture]. - Prise en charge des tests asynchrones.
Ce framework est particulièrement utile pour tester des fonctions mathématiques, des analyseurs syntaxiques (parsers) ou des algorithmes où il est nécessaire de vérifier de nombreux cas limites.
Property-based testing avec proptest
Le property-based testing (test basé sur les propriétés) est une méthode où vous décrivez des invariants (propriétés) qui doivent être vérifiés pour toutes les données d'entrée possibles. La bibliothèque proptest génère des données d'entrée aléatoires et vérifie ces propriétés.
Installation :
[dev-dependencies]proptest = "1.5"Exemple : vérifier que le tri conserve la longueur et tous les éléments :
use proptest::prelude::*;
proptest! { #[test] fn test_sort_keeps_elements(mut vec: Vec<i32>) { let original_len = vec.len(); let mut sorted = vec.clone(); sorted.sort(); assert_eq!(sorted.len(), original_len); for item in &vec { assert!(sorted.contains(item)); } }}Avantages de proptest :
- Génération automatique de milliers de scénarios aléatoires.
- Minimisation (shrink) — en cas d'échec du test, la bibliothèque réduit