Introduction
Les tests transforment une attente en preuve exécutable. Un test ciblé vérifie un comportement, compare le résultat obtenu au résultat attendu et sécurise les futures modifications en détectant automatiquement les régressions.
Vous allez ajouter des tests à une bibliothèque préparée de calcul de frais d’expédition. Les fonctions de production sont volontairement simples afin que vous puissiez vous concentrer sur l’emplacement des tests Rust, la manière dont les assertions expriment les attentes, les cas limites importants et la façon dont Cargo exécute une cible de test à la fois.
Ajouter un test unitaire ciblé
Dans cette étape, vous allez placer un test unitaire à côté du code de la bibliothèque, puis exécuter uniquement ce test nommé.
Le projet se trouve dans /home/labex/project/shipping-quote. Accédez à ce répertoire :
cd /home/labex/project/shipping-quote
Avant de modifier le fichier, examinez brièvement le code source de la bibliothèque. Ici, la commande sed -n '1,220p' sert uniquement à afficher le contenu sans le modifier : -n désactive l’affichage automatique et 1,220p affiche explicitement les lignes 1 à 220. Cette plage suffit pour afficher le fichier complet sans ouvrir d’éditeur :
sed -n '1,220p' src/lib.rs
La syntaxe #[...] désigne un attribut : des métadonnées attachées à l’élément Rust situé immédiatement en dessous. L’attribut #[cfg(test)] indique à Rust de compiler le module de tests suivant uniquement lors des compilations destinées aux tests. Un module est un conteneur nommé qui regroupe des éléments associés ; le prochain Guided Lab présente les modules comme outil général d’organisation.
Dans mod tests, le mot super désigne le module parent et * désigne tous les noms accessibles depuis ce parent. Ainsi, use super::*; rend les fonctions de la bibliothèque accessibles sous leur nom court dans le module de tests. Enfin, une fonction marquée par #[test] devient un test que Cargo peut détecter et exécuter.
Ouvrez le fichier source avec Nano :
nano src/lib.rs
Remplacez // FIRST_UNIT_TEST par ce petit test :
#[test]
fn light_parcel_costs_five() {
assert_eq!(shipping_cost(3), 5);
}
assert_eq! compare ses deux expressions. Si elles sont égales, le test continue ; sinon, il échoue et affiche les deux valeurs. Ici, le test indique qu’un colis de trois kilogrammes coûte cinq unités à expédier.
Enregistrez le fichier avec Ctrl+O, appuyez sur Entrée, puis quittez avec Ctrl+X. Transmettez le nom du test après cargo test pour exécuter uniquement les tests dont le nom contient ce texte :
cargo test light_parcel_costs_five
Cargo compile la version destinée aux tests et affiche le résultat du test unitaire nommé :
test tests::light_parcel_costs_five ... ok
test result: ok. 1 passed; 0 failed; ...
Le préfixe tests:: indique que le test se trouve dans le module de tests local de la bibliothèque, et ok confirme que son assertion a réussi.
Couvrir les cas limites
Dans cette étape, vous allez ajouter des tests aux limites où le comportement des frais d’expédition change.
Une valeur représentative telle que 3 vérifie un point situé dans la plage des colis légers, mais les bogues se cachent souvent aux limites. Dans le match préparé, 1..=5 est un motif de plage qui correspond à toute valeur comprise entre un et cinq, bornes incluses. Il réutilise la notation de plage inclusive des boucles dans un nouveau contexte de motif. La fonction traite zéro de manière particulière et conserve le tarif de cinq unités jusqu’à exactement cinq kilogrammes. Tester ces valeurs permet de vérifier les deux limites.
Ouvrez à nouveau la bibliothèque :
nano src/lib.rs
Remplacez // EDGE_UNIT_TESTS par ces deux tests courts :
#[test]
fn empty_parcel_is_free() {
assert_eq!(shipping_cost(0), 0);
}
#[test]
fn five_kilograms_is_still_light() {
assert_eq!(shipping_cost(5), 5);
}
Chaque test décrit une règle dans son nom et contient une seule assertion ciblée. Il est ainsi facile de localiser un échec. Enregistrez le fichier et quittez Nano.
Le filtre tests:: correspond aux noms complets des tests du module de tests unitaires local. Utilisez-le pour exécuter les trois tests unitaires tout en excluant pour le moment la cible de test d’intégration distincte :
cargo test tests::
Le résultat attendu est constitué de trois tests unitaires réussis :
test tests::empty_parcel_is_free ... ok
test tests::five_kilograms_is_still_light ... ok
test tests::light_parcel_costs_five ... ok
test result: ok. 3 passed; 0 failed; ...
Ensemble, ces exemples couvrent une valeur ordinaire et les deux limites importantes de la règle applicable aux colis légers.
Terminer un test d’intégration
Dans cette étape, vous allez tester la bibliothèque via son interface publique depuis un fichier distinct.
Les tests unitaires placés dans src/lib.rs sont proches de l’implémentation et peuvent utiliser les éléments internes du module parent. Les tests d’intégration se trouvent dans le répertoire de niveau supérieur tests/, sont compilés comme des programmes de test distincts et utilisent uniquement l’interface publique de la bibliothèque, comme le ferait un appelant externe. Le nom de paquet shipping-quote devient le nom de crate Rust shipping_quote, avec un caractère de soulignement, dans le code source. Le prochain Lab regroupe les notions de paquet, de crate, de module et de visibilité publique.
Examinez le squelette préparé du test d’intégration :
sed -n '1,160p' tests/order_workflow.rs
Il importe uniquement la fonction publique order_total, l’appelle pour une commande de 40 unités et un colis de trois kilogrammes, puis vous laisse une assertion à compléter. Ouvrez le fichier :
nano tests/order_workflow.rs
Remplacez la ligne d’assertion temporaire qui se termine par // INTEGRATION_ASSERTION par :
assert_eq!(total, 45);
Le total attendu additionne le sous-total de 40 unités et les frais d’expédition de cinq unités applicables à un colis léger. Enregistrez le fichier et quittez Nano.
L’option --test order_workflow sélectionne la cible de test d’intégration correspondant au fichier tests/order_workflow.rs :
cargo test --test order_workflow
La cible affiche son test du flux public :
test order_total_includes_shipping ... ok
test result: ok. 1 passed; 0 failed; ...
Enfin, exécutez toute la suite de tests du paquet sans filtre :
cargo test
Cargo exécute les trois tests unitaires et le test d’intégration. Il est normal d’obtenir des récapitulatifs distincts, car les tests s’exécutent dans des binaires de test différents ; chaque test nommé doit afficher ok et chaque récapitulatif doit indiquer zéro échec.
Résumé
Vous avez ajouté des tests unitaires locaux, couvert les limites des règles, terminé un test d’intégration via l’API publique de la bibliothèque et utilisé les filtres de Cargo pour exécuter un test, un module, une cible d’intégration ou la suite complète. Ces pratiques fournissent rapidement des preuves pendant le développement et renforcent la protection contre les régressions avant la livraison.


