Pourquoi le TDD en Rust n'est pas ennuyeux, mais avantageux ?
\n\nAvez-vous déjà écrit du code qui fonctionnait « en quelque sorte correctement », pour ensuite attraper un bug à l'endroit le plus inattendu ? Ça vous parle. Le développement piloté par les tests (TDD) est une méthode qui bouleverse le processus habituel. Au lieu d'écrire d'abord le code, puis de se demander s'il fonctionne, vous écrivez d'abord un test qui doit échouer, puis vous écrivez exactement assez de code pour que le test réussisse.
\n\nRust est un langage qui, déjà au niveau du compilateur, vous protège contre toute une classe d'erreurs (adieu les segfaults et les data races !). Mais même le compilateur ne garantit pas que votre logique est correcte. Le TDD en Rust ajoute à cette sécurité une couche supplémentaire : vous ne vous contentez pas d'écrire du code, vous documentez le comportement attendu directement dans les tests. Et c'est incroyablement génial.
\n\nDans cet article, nous allons décortiquer le TDD en Rust avec des exemples concrets. Vous verrez comment écrire des tests avant l'implémentation, comment les exécuter avec cargo test et comment refactoriser le code sans craindre de casser quoi que ce soit. C'est parti !
Qu'est-ce que le TDD et pourquoi Rust est-il idéal pour cela ?
\n\nTDD signifie Test-Driven Development (développement piloté par les tests). Le cycle est simple et élégant :
\n\n- \n
- Rouge — on écrit un test qui décrit une nouvelle fonctionnalité. On l'exécute — le test échoue (logique, le code n'existe pas encore). \n
- Vert — on écrit le code minimal pour que le test réussisse. On ne pense pas à la beauté, seulement à la réussite du test. \n
- Refactorisation — on améliore le code sans changer son comportement. Les tests restent verts. \n
Rust est parfaitement adapté au TDD pour plusieurs raisons :
\n- \n
- Système de test intégré —
cargo testfonctionne directement, pas besoin d'installer de frameworks externes. \n - Typage fort — le compilateur détecte les erreurs de type, et les tests détectent les erreurs logiques. Ensemble, ils sont imbattables. \n
- Possession et emprunt — les tests aident à s'assurer que vous gérez correctement la mémoire, sans créer de copies inutiles. \n
- Communauté et documentation — la communauté Rust promeut activement les tests, les exemples sont nombreux. \n
Configuration du projet pour le TDD
\n\nCréons un nouveau projet :
\ncargo new tdd_rust_example\ncd tdd_rust_example\n\nPar défaut, cargo new crée un fichier src/main.rs avec un programme très simple. Nous allons écrire une bibliothèque, donc nous le renommerons en src/lib.rs (ou simplement supprimer main.rs et créer lib.rs). Dans Cargo.toml, rien à changer — les tests sont déjà inclus.
D'ailleurs, si vous écrivez uniquement une bibliothèque (sans fichier exécutable), utilisez cargo new --lib.
Premier test : rouge
\n\nImaginez que nous voulions écrire une fonction qui additionne deux nombres. Selon le TDD, nous écrivons d'abord le test. Ouvrons src/lib.rs et ajoutons :
#[cfg(test)]\nmod tests {\n #[test]\n fn test_add() {\n let result = add(2, 3);\n assert_eq!(result, 5);\n }\n}\n\nExécutons :
\ncargo test\n\nVous verrez une erreur de compilation — la fonction add n'est pas définie. C'est normal. Nous sommes dans la zone rouge.
Vert : implémentation minimale
\n\nMaintenant, écrivons exactement assez de code pour que le test réussisse. Ajoutons la fonction add au-dessus du module de test :
fn add(a: i32, b: i32) -> i32 {\n a + b\n}\n\n#[cfg(test)]\nmod tests {\n use super::*;\n \n #[test]\n fn test_add() {\n let result = add(2, 3);\n assert_eq!(result, 5);\n }\n}\n\nNotez le use super::*; — cela importe tout du module parent (notre code) dans le module de test.
Exécutons à nouveau cargo test. Vert ! Le test réussit. Nous avons fait le minimum — retourné la somme. Il semble