単体テストを作成する

完了

Rust の単体テストは、テスト以外のコードが期待どおりに機能していることを検証する #[test] 属性でマークされた単純な関数です。 これらの関数は、コードをテストするときにのみコンパイルされます。

テスト関数によって、テストするコードが実行されます。 次に、結果がチェックされます。これには多くの場合、assert! または assert_eq! のいずれかのマクロが使用されます。

次のコード例では、単純な add 関数と、#[test] 属性でマークされた別の add_works 関数を定義します。

fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[test]
fn add_works() {
    assert_eq!(add(1, 2), 3);
    assert_eq!(add(10, 12), 22);
    assert_eq!(add(5, -2), 3);
}

コマンド $ cargo test を実行すると、出力は次の例のようになります。

running 1 test
test add_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

テスト不合格

単に cargo tests の動作を確認するために、失敗するテストを含めてみましょう。

#[test]
fn add_fails() {
    assert_eq!(add(2, 2), 7);
}

$ cargo test コマンドを使用してテストを再度実行すると、出力に add_works テストに合格したことが示されます。 また、add_fails が失敗したことが示され、assert_eq への呼び出しに失敗したことに関する情報が含まれます。

running 2 tests
test add_works ... ok
test add_fails ... FAILED

failures:

---- add_fails stdout ----
thread 'add_fails' panicked at 'assertion failed: `(left == right)`
  left: `4`,
 right: `7`', src/main.rs:14:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    add_fails

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

予想される失敗

多くのシナリオでは、条件によって panic! が発生するかどうかをテストすることが重要です。

属性 should_panic を使用すると、panic! を確認できます。 この属性をテスト関数に追加すると、関数内のコードがパニックになったときにテストが成功します。 コードがパニックにならないと、テストは失敗します。

ここで、add_fails テスト関数により、予想されるパニックがキャプチャされ、それが成功テストとして扱われます。

#[test]
#[should_panic]
fn add_fails() {
    assert_eq!(add(2, 2), 7);
}

テスト結果は次のようになります。

running 2 tests
test add_works ... ok
test add_fails ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

テストを無視する

[test] 属性の注釈が付けられた関数には、[ignore] 属性の注釈を付けることもできます。 この属性により、テスト中にテスト関数がスキップされます。

[ignore] 属性は、必要に応じて、テストが無視される理由と共に書き込むことができます。

#[test]
#[ignore = "not yet reviewed by the Q.A. team"]
fn add_negatives() {
    assert_eq!(add(-2, -2), -4)
}

無視されたテスト関数は引き続き型チェックされ、コンパイルされますが、テストで実行されることはありません。

running 3 tests
test add_negatives ... ignored
test add_works ... ok
test add_fails ... ok

test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out

テスト モジュール

ほとんどの単体テストは、#[cfg(test)] 属性によってサブモジュールに挿入されます。

fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod add_function_tests {
    use super::*;

    #[test]
    fn add_works() {
        assert_eq!(add(1, 2), 3);
        assert_eq!(add(10, 12), 22);
        assert_eq!(add(5, -2), 3);
    }

    #[test]
    #[should_panic]
    fn add_fails() {
        assert_eq!(add(2, 2), 7);
    }

    #[test]
    #[ignore]
    fn add_negatives() {
        assert_eq!(add(-2, -2), -4)
    }
}

cfg 属性により、条件付きコンパイルが制御され、述語が true の場合にのみ、それがアタッチされている内容がコンパイルされます。 test コンパイル フラグは、コマンド $ cargo test を実行するたびに Cargo によって自動的に発行されるため、テストの実行時に常に true になります。

add_function_tests モジュール内のコードが外部モジュール内の add にアクセスするには、use super::*; 宣言が必要です。

このユニットで使用されているコードは、この Rust Playground リンクで確認できます。