Rustでのテスト
Rustには自動テストを行うための仕組みが標準で備わっています。決まった書式でテストコードを書くと、cargo test
でテストを実行することができます。
テストケースの書き方
モジュールの宣言
テスト用のモジュールを宣言します。モジュールには#[cfg(test)]
というアトリビュートを付与する必要があります。
テスト用のモジュールは、テスト対象のモジュールとはスコープとは異なるので、use super::*;
と使うなどして参照できるようにするのが一般的です。
#[cfg(test)]
mod tests {
use super::*;
// ここにテストケースを書く
}
テストケースの作成
テストケースはfn
を使って関数の形で宣言します。各関数には#[test]
アトリビュートを付与して、テストケースであることを明記します。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
// アサーション
}
}
アサーション
テストケースは、その関数内でパニックが起これば失敗、そうでなければ成功と判定されます。
パニックの有無
ある値が想定した値と等しいことを検証するにはassert_eq!
マクロを使います。これは二つの引数を取り、その値が等しければ何もせず、等しくなければパニックを起こします。すなわち、テストケースの中でassert_eq!
を使うことで、等しい場合はテストケースが通り、そうでない場合はテストケースが失敗します。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn equality_test() {
assert_eq!(3 * 3, 9);
}
}
逆に、等しくないことを検証するにはassert_ne!
マクロを使います。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inequality_test() {
assert_ne!(3 * 3, 10);
}
}
単に、何かの値がtrue
であることを検証するにはassert!`マクロを使います。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn boolean_test() {
let is_valid = true;
assert!(is_valid);
}
}
Result
を使った判定
テストケースの戻り値にResult
を使うことができます。Ok
を返せば成功、Err
を返せば失敗とみなされます。そのため、例えばテストケース内で?
を使うことができます。
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn result_test() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("Calculation failed"))
}
}
}
パニックが起きることをテストする
パニックが起きることを検証したい場合は、テストケースに#[should_panic]
アトリビュートを付与します。
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn panic_test() {
panic!("This test should panic!");
}
}
TypeScriptではJestやVitestといったテストフレームワークに頼ることがほとんどですが、デフォルトでテスト機能を備えているのはうれしいです。スタンダードが決まっていると開発者ごとのブレも少なくなり、学習コストが下がります。
テストの実行
すべてのテストを実行する
cargo test
でテストを実行することができます。
cargo test
デフォルトではマルチスレッドで並列実行されます。並列なので直列で実行するよりも早く終わりますが、テストケース同士が影響しあうような場合は--test-threads
フラグで直列で実行させることができます。
cargo test -- --test-threads=1
一部のテストを実行する
テストケース(テスト関数)の名前を引数に渡すと、その名前を含むテストケースが実行されます(当てはまるものがすべて実行される)。
# 'foo'がテストケース名に含まれるものがすべて実行される
cargo test foo
一部のテストを実行しない
テストケースのアトリビュートに#[ignore]
を付与すると、そのテストケースはデフォルトで無視されるようになります。cargo test
を実行してもそのテストケースは実行されません。
cargo test -- --ignored
を実行すると、無視されているテストケースのみを実行します。
成功ケースの標準出力は抑止される
成功したテストケース内における標準出力はすべてキャプチャされ、コンソールには表示されません(失敗したテストケースについては表示されます)。
成功したケースに関しても表示したい場合はcargo test -- --nocapture
を実行します。