Comment puis-je écrire un test unitaire Rust qui s'assure qu'une panique s'est produite?
J'ai une fonction Rust qui panic
est sous certaines conditions et je souhaite écrire un cas de test pour valider si la fonction panique ou non. Je n'ai rien trouvé d'autre que les macros assert!
et assert_eq!
. Est-il un mécanisme pour tester cela?
Je pourrais générer une nouvelle tâche et vérifier si cette tâche panique ou non. Est-il judicieux?
Renvoyer un Result<T, E>
ne convient pas dans mon cas.
Je souhaite ajouter le support pour le trait Add
à un Matrix
type I suis mise en œuvre. La syntaxe idéale pour un tel ajout ressemblerait à:
let m = m1 + m2 + m3;
Où m1
, m2
, m3
sont toutes les matrices. Par conséquent, le type de résultat de add
devrait être Matrix
. Quelque chose comme ce qui suit serait trop cryptique:
let m = ((m1 + m2).unwrap() + m3).unwrap()
En même temps, la fonction add()
doit valider que les deux matrices ajoutées ont la même dimension. Ainsi, add()
doit paniquer si les dimensions ne correspondent pas. L'option disponible est panic!()
.
4 réponses
Vous pouvez trouver la réponse dans test section de la Rouille livre. Plus précisément, vous voulez #[should_panic]
attribut:
#[test]
#[should_panic]
fn test_invalid_matrices_multiplication() {
let m1 = Matrix::new(3, 4); // assume these are dimensions
let m2 = Matrix::new(5, 6);
m1 * m2
}
Comme Francis Gagné l'a mentionné dans sa réponse, je trouve aussi que l'attribut #[should_panic]
n'est pas assez fin pour des tests plus complexes-par exemple, si ma configuration de test échoue pour une raison quelconque (c'est-à-dire que j'ai écrit un mauvais test), je veux qu'une panique soit considérée comme un échec!
, Comme de la Rouille 1.9.0, std::panic::catch_unwind()
est disponible. Il vous permet de mettre le code que vous attendez de paniquer dans une fermeture, et seules les paniques lancées par que code seront considérées comme "attendues" (c'est-à-dire un passage test).
#[test]
fn test_something() {
... //<-- Any panics here will cause test failure (good)
let result = std::panic::catch_unwind(|| <expected_to_panic_operation_here>);
assert!(result.is_err()); //probe further for specific error type here, if desired
}
Notez qu'il ne peut pas attraper les paniques non-déroulantes (par exemple abandonner).
Si vous voulez affirmer que seule une partie spécifique de la fonction de test échoue, utilisez task::try()
et vérifier qu'elle renvoie un Err
, par exemple avec is_err()
. Dans les fonctions de test complexes, cela permet de s'assurer que le test ne passe pas par erreur en raison d'un échec précoce.
Plusieurs les tests dans la bibliothèque standard Rust elle-même utilisent cette technique.
En addendum: la solution proposée par @U007D fonctionne également dans doctests:
/// My identity function that panic for an input of 42.
///
/// ```
/// assert_eq!(my_crate::my_func(23), 23);
///
/// let result = std::panic::catch_unwind(|| my_crate::my_func(42));
/// assert!(result.is_err());
/// ```
pub fn my_func(input: u32) -> u32 {
if input == 42 {
panic!("Error message.");
} else {
input
}
}