Ich habe eine Rust-Funktion, die panic
unter bestimmten Bedingungen funktioniert, und ich möchte einen Testfall schreiben, um zu überprüfen, ob die Funktion in Panik gerät oder nicht. Ich konnte nichts außer den Makros assert!
und finden assert_eq!
. Gibt es einen Mechanismus, um dies zu testen?
Ich könnte eine neue Aufgabe erzeugen und prüfen, ob diese Aufgabe in Panik gerät oder nicht. Macht das Sinn?
Die Rücksendung von a Result<T, E>
ist in meinem Fall nicht geeignet.
Ich möchte Add
einem Matrix
Typ, den ich implementiere , Unterstützung für das Merkmal hinzufügen . Die ideale Syntax für eine solche Addition würde folgendermaßen aussehen:
let m = m1 + m2 + m3;
wo m1
, m2
, m3
sind alle Matrizen. Daher sollte der Ergebnistyp von add
sein Matrix
. So etwas wäre zu kryptisch:
let m = ((m1 + m2).unwrap() + m3).unwrap()
Gleichzeitig muss die add()
Funktion überprüfen, ob die beiden hinzugefügten Matrizen dieselbe Dimension haben. Daher add()
muss in Panik geraten, wenn die Abmessungen nicht übereinstimmen. Die verfügbare Option ist panic!()
.
quelle
#[should_panic(expected = "assertion failed")]
#[should_panic]
tatsächlich funktionierte. Wenn Sie ein Generikumcargo test
über die Befehlszeile ausführen , werden Sie feststellen, dass es die Panik verschluckt und nur als angezeigt wirdok
.Wie Francis Gagné in seiner Antwort erwähnt hat, finde ich das
#[should_panic]
Attribut auch für komplexere Tests nicht feinkörnig genug - wenn beispielsweise mein Testaufbau aus irgendeinem Grund fehlschlägt (dh ich habe einen schlechten Test geschrieben), tue ich dies Ich möchte, dass eine Panik als Misserfolg betrachtet wird!Ab Rust 1.9.0
std::panic::catch_unwind()
verfügbar. Es ermöglicht Ihnen, den Code, von dem Sie erwarten, dass er in Panik gerät, in einen Abschluss zu versetzen, und nur von diesem Code ausgegebene Panik wird als erwartet betrachtet (dh ein bestehender 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 }
Beachten Sie, dass es keine nicht abwickelnde Panik auslösen kann (z
std::process::abort()
. B. ).quelle
Wenn Sie behaupten möchten, dass nur ein bestimmter Teil der Testfunktion fehlschlägt, verwenden Sie
std::panic::catch_unwind()
und überprüfen Sie, ob einErr
Beispiel zurückgegeben wird, z. B. mitis_err()
. In komplexen Testfunktionen wird so sichergestellt, dass der Test nicht aufgrund eines frühen Fehlers fehlerhaft bestanden wird.Mehrere Tests in der Rust-Standardbibliothek selbst verwenden diese Technik.
quelle
assert_fails
oder einassert_panics
Makro geben?unwrap_err
.#[no_std]
Umgebung zu tun ? Ich möchte einassert_panics!
Makro für den allgemeinen Gebrauch erstellen .Als Nachtrag: Die von @ U007D vorgeschlagene Lösung funktioniert auch in Doktrinen:
/// 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 } }
quelle
Verwenden Sie Folgendes
catch_unwind_silent
anstelle von regulärcatch_unwind
, um für erwartete Ausnahmen eine Stille in der Ausgabe zu erzielen:use std::panic; fn catch_unwind_silent<F: FnOnce() -> R + panic::UnwindSafe, R>(f: F) -> std::thread::Result<R> { let prev_hook = panic::take_hook(); panic::set_hook(Box::new(|_| {})); let result = panic::catch_unwind(f); panic::set_hook(prev_hook); result }
quelle