web-dev-qa-db-ja.com

パニックが発生したことを確認するRust単体テストを書くにはどうすればよいですか?

Rustある条件下でpanicsの関数があり、その関数がパニック状態になっているかどうかを検証するためのテストケースを作成したいと思います。 _assert!_および_assert_eq!_マクロ:これをテストするためのメカニズムはありますか?

新しいタスクを生成し、そのタスクがパニックになるかどうかを確認できます。理にかなっていますか?


私の場合、_Result<T, E>_を返すのは適切ではありません。

実装しているAdd型にMatrix特性のサポートを追加したいと思います。このような追加の理想的な構文は次のようになります。

_let m = m1 + m2 + m3;
_

ここで、_m1_、_m2_、_m3_はすべて行列です。したがって、addの結果タイプはMatrixでなければなりません。次のようなものはわかりにくいでしょう。

_let m = ((m1 + m2).unwrap() + m3).unwrap()
_

同時に、add()関数は、追加される2つの行列の次元が同じであることを検証する必要があります。したがって、次元が一致しない場合、add()はパニックする必要があります。利用可能なオプションはpanic!()です。

57
Shailesh Kumar

答えは、Rust本の testing セクションにあります。具体的には、#[should_panic]属性:

#[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
}
80

FrancisGagnéが答えで述べたように、_#[should_panic]_属性は、より複雑なテストには十分にきめ細かくないこともわかります。たとえば、何らかの理由でテストのセットアップが失敗した場合(つまり、テスト)、Idoパニックを失敗と見なしたい!

Rust 1.9.0、 std::panic::catch_unwind() が利用可能になりました。これにより、パニックが発生する可能性のあるコードをクロージャに入れることができます。 thatコードによって発せられたパニックは、期待される(つまり、テストに合格した)と見なされます。

_#[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
}
_

巻き戻さないパニックをキャッチできないことに注意してください(例:std::process::abort())。

30
U007D

テスト関数の特定の部分のみが失敗することを表明したい場合は、 std::panic::catch_unwind() を使用し、Err、たとえば is_err() で。複雑なテスト機能では、これにより、早期の失敗が原因でテストが誤ってパスしないようにすることができます。

いくつかのtests Rust標準ライブラリ自体がこの手法を使用します。

14
Francis Gagné

補遺として:@ U007Dが提案するソリューションは、doctestでも機能します。

/// 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
    }
}
4
m00am