テスト
ご存じのとおり、テストはあらゆるソフトウェアに不可欠です!Rust はユニットテストとインテグレーションテストをファーストクラスでサポートしています(TRPL のこの章を参照)。
上記でリンクされているテストの章から、ユニットテストとインテグレーションテストの書き方がわかります。構成としては、ユニットテストはテスト対象のモジュール内に配置でき、インテグレーションテストは専用の tests/ ディレクトリに配置できます。
foo
├── Cargo.toml
├── src
│ └── main.rs
│ └── lib.rs
└── tests
├── my_test.rs
└── my_other_test.rs
tests 内の各ファイルは個別のインテグレーションテストです。つまり、依存クレートから呼び出されるかのようにライブラリをテストすることを目的としたテストです。
テストの章では、3 つの異なるテストスタイルであるユニット、ドキュメント、インテグレーションについて詳しく説明しています。
cargo は当然ながら、すべてのテストを実行する簡単な方法を提供しています!
$ cargo test
次のような出力が表示されるはずです。
$ cargo test
Compiling blah v0.1.0 (file:///nobackup/blah)
Finished dev [unoptimized + debuginfo] target(s) in 0.89 secs
Running target/debug/deps/blah-d3b32b97275ec472
running 4 tests
test test_bar ... ok
test test_baz ... ok
test test_foo_bar ... ok
test test_foo ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
名前がパターンに一致するテストを実行することもできます。
$ cargo test test_foo
$ cargo test test_foo
Compiling blah v0.1.0 (file:///nobackup/blah)
Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs
Running target/debug/deps/blah-d3b32b97275ec472
running 2 tests
test test_foo ... ok
test test_foo_bar ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out
注意点が 1 つあります。Cargo は複数のテストを並行して実行する場合があるため、テスト同士が競合しないようにしてください。
この並行性が問題を引き起こす例の 1 つは、以下のように 2 つのテストが 1 つのファイルに出力する場合です。
#![allow(unused)] fn main() { #[cfg(test)] mod tests { // 必要なモジュールをインポートする use std::fs::OpenOptions; use std::io::Write; // このテストはファイルに書き込む #[test] fn test_file() { // ファイル ferris.txt を開く。存在しない場合は作成する。 let mut file = OpenOptions::new() .append(true) .create(true) .open("ferris.txt") .expect("Failed to open ferris.txt"); // "Ferris" を 5 回出力する。 for _ in 0..5 { file.write_all("Ferris\n".as_bytes()) .expect("Could not write to ferris.txt"); } } // このテストは同じファイルに書き込もうとする #[test] fn test_file_also() { // ファイル ferris.txt を開く。存在しない場合は作成する。 let mut file = OpenOptions::new() .append(true) .create(true) .open("ferris.txt") .expect("Failed to open ferris.txt"); // "Corro" を 5 回出力する。 for _ in 0..5 { file.write_all("Corro\n".as_bytes()) .expect("Could not write to ferris.txt"); } } } }
意図としては次の結果を得ることです。
$ cat ferris.txt
Ferris
Ferris
Ferris
Ferris
Ferris
Corro
Corro
Corro
Corro
Corro
実際に ferris.txt に書き込まれるのは次の内容です。
$ cargo test test_file && cat ferris.txt
Corro
Ferris
Corro
Ferris
Corro
Ferris
Corro
Ferris
Corro
Ferris