導入
「動いているつもり」のコードが、実は間違っていた——というのはどの言語でもよくある話です。Rust では、外部のテストフレームワークを別途入れなくても、言語とツールチェーンに最初からテストの仕組みが同梱されています。だからこそ実務のRustプロジェクトでは、テストを書くハードルがとても低くなっています。
説明
テストの核になるのが assert! 系のマクロです。条件が満たされなければ、その場でパニックしてテストが失敗したと知らせてくれます。
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn is_even(n: i32) -> bool {
n % 2 == 0
}
fn main() {
assert_eq!(add(2, 3), 5); // 左辺と右辺が等しいことを確認
assert_eq!(add(-1, 1), 0);
assert!(is_even(4)); // 条件が true であることを確認
assert!(!is_even(7));
// assert_ne!(add(1, 1), 3); // 左辺と右辺が異なることを確認(今回は省略)
println!("all tests passed");
}
assert_eq!(実際の値, 期待する値)… 一致しなければ、両方の値を表示してパニックします。値を突き合わせる一番よく使う形です。assert!(条件)… 条件がfalseならパニックします。真偽値を確認したいときに使います。assert_ne!(a, b)…aとbが等しくないことを確認します(assert_eq!の逆)。
実際のRustプロジェクトでは、こうしたチェックを main の中に埋め込むのではなく、#[test] を付けた専用の関数として書きます。
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[test]
fn test_add_positive() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_add_negative() {
assert_eq!(add(-1, 1), 0);
}
#[test] を付けた関数は、通常の実行(cargo run)では呼ばれず、cargo test を実行したときにだけ集めて実行されます。全部パスすれば test result: ok、失敗したテストがあれば FAILED とその内容が表示されます。1つのファイルの中に何個でも #[test] 関数を書けるので、機能を作るたびにテストも一緒に増やしていくのが実務の流儀です。
補足:このコースの実行環境は
fn mainを直接動かす学習用シミュレータなので、#[test]関数は自動では実行されません。実際の挙動を体験するには、上のコードのようにmainの中でassert_eq!/assert!を直接呼んで確認します。本物のプロジェクトでは#[test]+cargo testの形で書くのが基本だと覚えておいてください。
やってみよう
下のエディタで add や is_even の実装を意図的に間違えてみて、assert_eq!/assert! がどのパニックメッセージを出すか確かめてみましょう。
演習
n を受け取り2乗した値を返す関数 square(n: i32) -> i32 を定義してください。assert_eq! で square(3) が 9 に、square(-4) が 16 になることを確認し、両方成功したら println!("ok") と出力してください。
ヒント1を見る
fn square(n: i32) -> i32 { n * n } のように定義します。
ヒント2を見る
assert_eq!(square(3), 9); assert_eq!(square(-4), 16); を main の中で呼んだ後、println!("ok"); します。