テスト

さて,pushpop を書き終えたので,次は書いたコードを実際にテストしてみましょう! Rust と cargo は,ファーストクラスの機能としてテストをサポートしているので,これは非常に簡単です. 関数を書いて,#[test] というアノテーション (注釈) を付けるだけでいいんです.

一般的に,Rust コミュニティではテストはテストされるコードの隣におくのが慣習です. しかし「本当の」コードとの衝突を避けるために,通常テスト用に新しい名前空間を作ります. first.rslib.rs に含まれるよう指定するために mod を使いましたが, mod はインラインで全く新しいファイルを作成することにも使用することができます.

// in first.rs

mod test {
    #[test]
    fn basics() {
        // TODO
    }
}

cargo test コマンドで呼び出します.

> cargo test
   Compiling lists v0.1.0 (/Users/ABeingessner/dev/temp/lists)
    Finished dev [unoptimized + debuginfo] target(s) in 1.00s
     Running /Users/ABeingessner/dev/lists/target/debug/deps/lists-86544f1d97438f1f

running 1 test
test first::test::basics ... ok

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

やったー!何もしないテストに合格しました! では,何かをするテストにしていきましょう. そのために assert_eq! マクロを利用します. これは特別なテストの魔法ではありません. このマクロがすることは,与えられた2つのものを比較し,一致しない場合はプログラムをパニックするということだけです. パニックを起こすことで,テストハーネスに失敗を示すのです.

mod test {
    #[test]
    fn basics() {
        let mut list = List::new();

        // 空のリストが正しい振る舞いをするか
        assert_eq!(list.pop(), None);

        // リストに要素を詰める
        list.push(1);
        list.push(2);
        list.push(3);

        // 削除が機能するか
        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        // 何も破損していないことを確かめるために,さらに要素をプッシュする
        list.push(4);
        list.push(5);

        // 削除が機能するか
        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        // リストが空になるか
        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }
}
> cargo test

error[E0433]: failed to resolve: use of undeclared type or module `List`
  --> src/first.rs:43:24
   |
43 |         let mut list = List::new();
   |                        ^^^^ use of undeclared type or module `List`


おっと.新しいモジュールを作ったので,リストを使うには明示的にそれを引き込む必要があります.

mod test {
    use super::List;
    // 他は全部同じ
}
> cargo test

warning: unused import: `super::List`
  --> src/first.rs:45:9
   |
45 |     use super::List;
   |         ^^^^^^^^^^^
   |
   = note: #[warn(unused_imports)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.43s
     Running /Users/ABeingessner/dev/lists/target/debug/deps/lists-86544f1d97438f1f

running 1 test
test first::test::basics ... ok

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

やった!

しかし,super::List が使用されていないという警告が出ているのは,どういうことでしょう…? どう考えてもテストの中で使ってますよね.

…テストの時だけですけどね! コンパイラを喜ばせるために(そしてユーザに優しくするために)テストを実行する時だけ,テストモジュールをコンパイルするように指示する必要があります.

#[cfg(test)]
mod test {
    use super::List;
    // 他は全部同じ
}

これでテストは完璧です!