#19 Tests
#[test], assert, cargo test
Votre premier test
En Rust, les tests sont des fonctions annotées avec #[test]. Ils vivent dans le même fichier que le code qu'ils testent, dans un module spécial tests.
// src/lib.rs
pub fn addition(a: i32, b: i32) -> i32 {
a + b
}
// Le module de tests
#[cfg(test)] // compilé uniquement pour les tests
mod tests {
use super::*; // importer les fonctions du module parent
#[test]
fn test_addition() {
let resultat = addition(2, 3);
assert_eq!(resultat, 5);
}
}L'attribut #[cfg(test)] indique que ce module n'est compilé que pendant cargo test. Il n'alourdit pas votre binaire final.
Les macros assert
Rust fournit plusieurs macros pour vérifier les résultats dans vos tests.
#[cfg(test)]
mod tests {
#[test]
fn test_assert_basique() {
// assert! : vérifie qu'une condition est vraie
assert!(2 + 2 == 4);
assert!(true);
}
#[test]
fn test_assert_eq_ne() {
// assert_eq! : vérifie l'égalité
assert_eq!(2 + 2, 4);
assert_eq!("bonjour", "bonjour");
// assert_ne! : vérifie la non-égalité
assert_ne!(2 + 2, 5);
}
#[test]
fn test_messages_personnalises() {
let age = 25;
// Message personnalisé en cas d'échec
assert!(age >= 18, "L'âge {} est inférieur à 18", age);
assert_eq!(age, 25, "L'âge devrait être 25, pas {}", age);
}
#[test]
#[should_panic] // Ce test DOIT paniquer pour réussir
fn test_division_par_zero() {
diviser(10, 0);
}
#[test]
#[should_panic(expected = "division par zéro")]
fn test_panic_message() {
diviser(10, 0); // doit paniquer avec ce message
}
fn diviser(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("division par zéro");
}
a / b
}
}Tester avec Result
Les tests peuvent aussi retourner un Result, ce qui permet d'utiliser l'opérateur ? au lieu de unwrap().
#[cfg(test)]
mod tests {
use std::num::ParseIntError;
#[test]
fn test_parse_nombre() -> Result<(), ParseIntError> {
let nombre: i32 = "42".parse()?;
assert_eq!(nombre, 42);
Ok(()) // le test réussit si Ok(()) est retourné
}
#[test]
fn test_operations() -> Result<(), String> {
let x = 10;
let y = 20;
if x + y != 30 {
return Err(String::from("La somme devrait être 30"));
}
Ok(())
}
}Ignorer des tests
#[test]
#[ignore] // Ce test est ignoré par défaut
fn test_lent() {
// Opération qui prend du temps...
std::thread::sleep(std::time::Duration::from_secs(10));
assert!(true);
}
// Pour exécuter les tests ignorés :
// $ cargo test -- --ignored
// Pour exécuter TOUS les tests (y compris ignorés) :
// $ cargo test -- --include-ignoredTests d'intégration
Les tests d'intégration vivent dans un dossier tests/ à la racine du projet. Ils testent votre bibliothèque comme un utilisateur externe.
mon-projet/
├── Cargo.toml
├── src/
│ └── lib.rs # code de la bibliothèque
└── tests/
├── integration_test.rs # test d'intégration
└── common/
└── mod.rs # utilitaires partagés entre tests// Pas besoin de #[cfg(test)] ici !
// Le dossier tests/ est automatiquement en mode test.
use testing_demo; // importer votre crate
#[test]
fn test_addition_integration() {
// Tester l'API publique de votre bibliothèque
assert_eq!(testing_demo::addition(10, 20), 30);
}
#[test]
fn test_workflow_complet() {
let a = testing_demo::addition(5, 5);
let b = testing_demo::addition(a, 10);
assert_eq!(b, 20);
}// Utilitaires partagés entre tests d'intégration
pub fn setup() {
// Préparer l'environnement de test
println!("Configuration du test...");
}
pub fn donnees_test() -> Vec<i32> {
vec![1, 2, 3, 4, 5]
}Exécuter les tests
cargo test est la commande principale. Elle offre de nombreuses options pour filtrer et configurer l'exécution des tests.
# Exécuter tous les tests
$ cargo test
# Afficher les println! pendant les tests
$ cargo test -- --nocapture
# Exécuter un test spécifique par nom
$ cargo test test_addition
# Exécuter les tests qui contiennent un motif
$ cargo test division
# Exécuter les tests d'un module spécifique
$ cargo test tests::
# Exécuter sur un seul thread (séquentiel)
$ cargo test -- --test-threads=1
# Exécuter seulement les tests d'intégration
$ cargo test --test integration_test
# Lister tous les tests sans les exécuter
$ cargo test -- --listÀ vous de jouer
Essayez les commandes ci-dessous pour exécuter les tests :