テストの記述法
テストは、非テストコードが想定された方法で機能していることを実証するRustの関数です。 テスト関数の本体は、典型的には以下の3つの動作を行います:
- 必要なデータや状態をセットアップする。
- テスト対象のコードを走らせる。
- 結果が想定通りかアサーションする。
Rustが、特にこれらの動作を行うテストを書くために用意している機能を見ていきましょう。
これには、test
属性、いくつかのマクロ、should_panic
属性が含まれます。
テスト関数の解剖
最も単純には、Rustにおけるテストはtest
属性で注釈された関数のことです。属性とは、
Rustコードの欠片に関するメタデータです; 一例を挙げれば、構造体とともに第5章で使用したderive
属性です。
関数をテスト関数に変えるには、fn
の前に#[test]
を付け加えるのです。
cargo test
コマンドでテストを実行したら、コンパイラはtest
属性で注釈された関数を走らせるテスト用バイナリをビルドし、
各テスト関数が通過したか失敗したかを報告します。
第7章で、Cargoで新規ライブラリプロジェクトを作成した時に、テスト関数が含まれるテストモジュールが自動で生成されたことを見かけました。 このモジュールのおかげでテストを書き始めることができるので、新しいプロジェクトを立ち上げる度に、 テスト関数の正確な構造と記法を調べる必要がなくなるわけです。必要なだけ追加のテスト関数とテストモジュールは追記することができます。
実際にテストすることなしにテンプレートのテストが生成されるのを実験することでテストの動作法の一部の側面を探究しましょう。 それから、自分で書いた何らかのコードを呼び出し、振る舞いが正しいかアサーションする現実世界のテストを書きましょう。
adder
という新しいライブラリプロジェクトを生成しましょう:
$ cargo new adder --lib
Created library `adder` project
$ cd adder
adder
ライブラリのsrc/lib.rsファイルの中身は、リスト11-1のような見た目のはずです。
ファイル名: src/lib.rs
# fn main() {} #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } }
とりあえず、最初の2行は無視し、関数に集中してその動作法を見ましょう。
fn
行の#[test]
注釈に注目してください: この属性は、これがテスト関数であることを示唆しますので、
テスト実行機はこの関数をテストとして扱うとわかるのです。さらに、tests
モジュール内には非テスト関数を入れ込み、
一般的なシナリオをセットアップしたり、共通の処理を行う手助けをしたりもできるので、
#[test]
属性でどの関数がテストかを示唆する必要があるのです。
関数本体は、assert_eq!
マクロを使用して、2 + 2が4に等しいことをアサーションしています。
このアサーションは、典型的なテストのフォーマット例をなしているわけです。走らせてこのテストが通ることを確かめましょう。
cargo test
コマンドでプロジェクトにあるテストが全て実行されます。リスト11-2に示したようにですね。
$ cargo test
Compiling adder v0.1.0 (file:///projects/adder)
Finished dev [unoptimized + debuginfo] target(s) in 0.22 secs
Running target/debug/deps/adder-ce99bcc2479f4607
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests adder
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Cargoがテストをコンパイルし、走らせました。Compiling
, Finished
, Running
の行の後にrunning 1 test
の行があります。
次行が、生成されたテスト関数のit_works
という名前とこのテストの実行結果、ok
を示しています。
テスト実行の総合的なまとめが次に出現します。test result:ok.
というテキストは、
全テストが通ったことを意味し、1 passed; 0 failed
と読める部分は、通過または失敗したテストの数を合計しているのです。
無視すると指定したテストは何もなかったため、まとめは0 ignored
と示しています。
また、実行するテストにフィルタをかけもしなかったので、まとめの最後に0 filtered out
と表示されています。
テストを無視することとフィルタすることに関しては次の節、「テストの実行され方を制御する」で語ります。
0 measured
という統計は、パフォーマンスを測定するベンチマークテスト用です。
ベンチマークテストは、本書記述の時点では、ナイトリ版のRustでのみ利用可能です。
詳しくは、ベンチマークテストのドキュメンテーションを参照されたし。
テスト出力の次の部分、つまりDoc-tests adder
で始まる部分は、ドキュメンテーションテストの結果用のものです。
まだドキュメンテーションテストは何もないものの、コンパイラは、APIドキュメントに現れたどんなコード例もコンパイルできます。
この機能により、ドキュメントとコードを同期することができるわけです。ドキュメンテーションテストの書き方については、
第14章の「テストとしてのドキュメンテーションコメント」節で議論しましょう。今は、Doc-tests
出力は無視します。
テストの名前を変更してどうテスト出力が変わるか確かめましょう。it_works
関数を違う名前、exploration
などに変えてください。
そう、以下のように:
ファイル名: src/lib.rs
# fn main() {} #[cfg(test)] mod tests { #[test] fn exploration() { assert_eq!(2 + 2, 4); } }
そして、cargo test
を再度走らせます。これで出力がit_works
の代わりにexploration
と表示しています:
running 1 test
test tests::exploration ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
別のテストを追加しますが、今回は失敗するテストにしましょう!テスト関数内の何かがパニックすると、
テストは失敗します。各テストは、新規スレッドで実行され、メインスレッドが、テストスレッドが死んだと確認した時、
テストは失敗と印づけられます。第9章でパニックを引き起こす最も単純な方法について語りました。
要するに、panic!
マクロを呼び出すことです。src/lib.rsファイルがリスト11-3のような見た目になるよう、
新しいテストanother
を入力してください。
ファイル名: src/lib.rs
# fn main() {} #[cfg(test)] mod tests { #[test] fn exploration() { assert_eq!(2 + 2, 4); } #[test] fn another() { //このテストを失敗させる panic!("Make this test fail"); } }
cargo test
で再度テストを走らせてください。出力はリスト11-4のようになるはずであり、
exploration
テストは通り、another
は失敗したと表示されます。
running 2 tests
test tests::exploration ... ok
test tests::another ... FAILED
failures:
---- tests::another stdout ----
thread 'tests::another' panicked at 'Make this test fail', src/lib.rs:10:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
tests::another
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
error: test failed
ok
の代わりにtest test::another
の行は、FAILED
を表示しています。個々の結果とまとめの間に、
2つ新たな区域ができました: 最初の区域は、失敗したテスト各々の具体的な理由を表示しています。
今回の場合、another
は'Make this test fail'でパニックした
ために失敗し、
これは、src/lib.rsファイルの10行で起きました。次の区域は失敗したテストの名前だけを列挙しています。
これは、テストがたくさんあり、失敗したテストの詳細がたくさん表示されるときに有用になります。
失敗したテストの名前を使用してそのテストだけを実行し、より簡単にデバッグすることができます。
テストの実行方法については、「テストの実行され方を制御する」節でもっと語りましょう。
サマリー行が最後に出力されています: 総合的に言うと、テスト結果は失敗
でした。
一つのテストが通り、一つが失敗したわけです。
異なる筋書きでのテスト結果がどんな風になるか見てきたので、テストを行う際に有用になるpanic!
以外のマクロに目を向けましょう。
assert!
マクロで結果を確認する
assert!
マクロは、標準ライブラリで提供されていますが、テスト内の何らかの条件がtrue
と評価されることを確かめたいときに有効です。
assert!
マクロには、論理値に評価される引数を与えます。その値がtrue
なら、
assert!
は何もせず、テストは通ります。その値がfalse
なら、assert!
マクロはpanic!
マクロを呼び出し、
テストは失敗します。assert!
マクロを使用することで、コードが意図した通りに機能していることを確認する助けになるわけです。
第5章のリスト5-15で、Rectangle
構造体とcan_hold
メソッドを使用しました。リスト11-5でもそれを繰り返しています。
このコードをsrc/lib.rsファイルに放り込み、assert!
マクロでそれ用のテストを何か書いてみましょう。
ファイル名: src/lib.rs
# fn main() {} #[derive(Debug)] pub struct Rectangle { length: u32, width: u32, } impl Rectangle { pub fn can_hold(&self, other: &Rectangle) -> bool { self.length > other.length && self.width > other.width } }
can_hold
メソッドは論理値を返すので、assert!
マクロの完璧なユースケースになるわけです。
リスト11-6で、長さが8、幅が7のRectangle
インスタンスを生成し、これが長さ5、
幅1の別のRectangle
インスタンスを保持できるとアサーションすることでcan_hold
を用いるテストを書きます。
ファイル名: src/lib.rs
# fn main() {} #[cfg(test)] mod tests { use super::*; #[test] fn larger_can_hold_smaller() { let larger = Rectangle { length: 8, width: 7 }; let smaller = Rectangle { length: 5, width: 1 }; assert!(larger.can_hold(&smaller)); } }
tests
モジュール内に新しい行を加えたことに注目してください: use super::*
です。
tests
モジュールは、第7章の「プライバシー規則」節で講義した通常の公開ルールに従う普通のモジュールです。
tests
モジュールは、内部モジュールなので、外部モジュール内のテスト配下にあるコードを内部モジュールのスコープに持っていく必要があります。
ここではglobを使用して、外部モジュールで定義したもの全てがこのtests
モジュールでも使用可能になるようにしています。
テストはlarger_can_hold_smaller
と名付け、必要なRectangle
インスタンスを2つ生成しています。
そして、assert!
マクロを呼び出し、larger.can_hold(&smaller)
の呼び出し結果を渡しました。
この式は、true
を返すと考えられるので、テストは通るはずです。確かめましょう!
running 1 test
test tests::larger_can_hold_smaller ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
通ります!別のテストを追加しましょう。今回は、小さい四角形は、より大きな四角形を保持できないことをアサーションします。
ファイル名: src/lib.rs
# fn main() {} #[cfg(test)] mod tests { use super::*; #[test] fn larger_can_hold_smaller() { // --snip-- } #[test] fn smaller_cannot_hold_larger() { let larger = Rectangle { length: 8, width: 7 }; let smaller = Rectangle { length: 5, width: 1 }; assert!(!smaller.can_hold(&larger)); } }
今回の場合、can_hold
関数の正しい結果はfalse
なので、その結果をassert!
マクロに渡す前に反転させる必要があります。
結果として、can_hold
がfalse
を返せば、テストは通ります。
running 2 tests
test tests::smaller_cannot_hold_larger ... ok
test tests::larger_can_hold_smaller ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
通るテストが2つ!さて、コードにバグを導入したらテスト結果がどうなるか確認してみましょう。
長さを比較する大なり記号を小なり記号で置き換えてcan_hold
メソッドの実装を変更しましょう:
# fn main() {} # #[derive(Debug)] # pub struct Rectangle { # length: u32, # width: u32, # } // --snip-- impl Rectangle { pub fn can_hold(&self, other: &Rectangle) -> bool { self.length < other.length && self.width > other.width } }
テストを実行すると、以下のような出力をします:
running 2 tests
test tests::smaller_cannot_hold_larger ... ok
test tests::larger_can_hold_smaller ... FAILED
failures:
---- tests::larger_can_hold_smaller stdout ----
thread 'tests::larger_can_hold_smaller' panicked at 'assertion failed:
larger.can_hold(&smaller)', src/lib.rs:22:8
(スレッド'tests::larger_can_hold_smallerはsrc/lib.rs:22:8の'assertion failed: larger.can_hold(&smaller)'
でパニックしました)
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
tests::larger_can_hold_smaller
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
テストによりバグが捕捉されました!larger.length
が8、smaller.length
が5なので、
can_hold
内の長さの比較が今はfalse
を返すようになったのです: 8は5より小さくないですからね。
assert_eq!
とassert_ne!
マクロで等値性をテストする
機能をテストする一般的な方法は、テスト下にあるコードの結果をコードが返すと期待される値と比較して、
等しいと確かめることです。これをassert
マクロを使用して==
演算子を使用した式を渡すことで行うこともできます。
しかしながら、これはありふれたテストなので、標準ライブラリには1組のマクロ(assert_eq!
とassert_ne!
)が提供され、
このテストをより便利に行うことができます。これらのマクロはそれぞれ、二つの引数を等値性と非等値性のために比較します。
また、アサーションが失敗したら二つの値の出力もし、テストが失敗した原因を確認しやすくなります。
一方でassert!
マクロは、==
式の値がfalse
値になったことしか示唆せず、false
値に導いた値は出力しません。
リスト11-7において、引数に2
を加えて結果を返すadd_two
という名前の関数を書いています。
そして、assert_eq!
マクロでこの関数をテストしています。
ファイル名: src/lib.rs
# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } #[cfg(test)] mod tests { use super::*; #[test] fn it_adds_two() { assert_eq!(4, add_two(2)); } }
テストが通ることを確認しましょう!
running 1 test
test tests::it_adds_two ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
assert_eq!
マクロに与えた第1引数の4
は、add_two(2)
の呼び出し結果と等しいです。
このテストの行はtest tests::it_adds_two ... ok
であり、ok
というテキストはテストが通ったことを示しています!
コードにバグを仕込んで、assert_eq!
を使ったテストが失敗した時にどんな見た目になるのか確認してみましょう。
add_two
関数の実装を代わりに3
を足すように変えてください:
# fn main() {} pub fn add_two(a: i32) -> i32 { a + 3 }
テストを再度実行します:
running 1 test
test tests::it_adds_two ... FAILED
failures:
---- tests::it_adds_two stdout ----
thread 'tests::it_adds_two' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `5`', src/lib.rs:11:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
tests::it_adds_two
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
テストがバグを捕捉しました!it_adds_two
のテストは失敗し、assertion failed: `(left == right)`
というメッセージを表示し、
left
は4
で、right
は5
だったと示しています。このメッセージは有用で、デバッグを開始する助けになります:
assert_eq!
のleft
引数は4
だったが、add_two(2)
があるright
引数は5
だったことを意味しています。
二つの値が等しいとアサーションを行う関数の引数は、
expected
とactual
と呼ばれ、引数を指定する順序が問題になる言語やテストフレームワークもあることに注意してください。
ですがRustでは、left
とright
と呼ばれ、期待する値とテスト下のコードが生成する値を指定する順序は、
問題になりません。assert_eq!(add_two(2), 4)
と今回のテストのアサーションを書くこともでき、
そうすると失敗メッセージは、assertion failed: `(left == right)`
となり、
left
が5
でright
が4
と表示されるわけです。
assert_ne!
マクロは、与えた2つの値が等しくなければ通り、等しければ失敗します。
このマクロは、値が何になるだろうか確信が持てないけれども、コードが意図した通りに動いていれば、
確実にこの値にはならないだろうとわかっているような場合に最も有用になります。例えば、
入力を何らかの手段で変えることが保障されているけれども、入力が変更される方法がテストを実行する曜日に依存する関数をテストしているなら、
アサーションすべき最善の事柄は、関数の出力が入力と等しくないことかもしれません。
表面下では、assert_eq!
とassert_ne!
マクロはそれぞれ、==
と!=
演算子を使用しています。
アサーションが失敗すると、これらのマクロは引数をデバッグフォーマットを使用して出力するので、
比較対象の値はPartialEq
とDebug
トレイトを実装していなければなりません。
組み込み型の全部と、標準ライブラリの型はほぼ全てこれらのトレイトを実装しています。
自分で定義した構造体とenumについては、PartialEq
を実装して、
その型の値が等しいか等しくないかアサーションする必要があるでしょう。Debug
を実装して、
アサーションが失敗した時に値を出力する必要もあるでしょう。
第5章のリスト5-12で触れたように、どちらのトレイトも導出可能なトレイトなので、
これは通常、構造体やenum定義に#[derive(PartialEq, Debug)]
という注釈を追加するくらい単純になります。
これらや他の導出可能なトレイトに関する詳細については、付録Cをご覧ください。
カスタムの失敗メッセージを追加する
さらに、assert!
、assert_eq!
、assert_ne!
の追加引数として、失敗メッセージと共にカスタムのメッセージが表示されるよう、
追加することもできます。assert!
の1つの必須引数、
あるいはassert_eq!
とassert_ne!
の2つの必須引数の後に指定された引数はどれもformat!
マクロに明け渡されるので、
(format!マクロについては第8章の「+
演算子または、format!
マクロで連結する」節で議論しました)、
{}
プレースホルダーを含むフォーマット文字列とこのプレースホルダーに置き換えられる値を渡すことができます。
カスタムメッセージは、アサーションがどんな意味を持つかドキュメント化するのに役に立ちます;
テストが失敗した時、問題が何なのかコードと共により良い考えを持てるでしょう。
例として、人々に名前で挨拶をする関数があり、関数に渡した名前が出力に出現することをテストしたいとしましょう:
ファイル名: src/lib.rs
# fn main() {} pub fn greeting(name: &str) -> String { // こんにちは、{}さん! format!("Hello {}!", name) } #[cfg(test)] mod tests { use super::*; #[test] fn greeting_contains_name() { let result = greeting("Carol"); assert!(result.contains("Carol")); } }
このプログラムの必要事項はまだ合意が得られておらず、挨拶の先頭のHello
というテキストは変わるだろうということは極めて確かです。
要件が変わった時にテストを更新しなくてもよいようにしたいと決定したので、
greeting
関数から返る値と正確な等値性を確認するのではなく、出力が入力引数のテキストを含むことをアサーションするだけにします。
greeting
がname
を含まないように変更してこのコードにバグを仕込み、このテストの失敗がどんな見た目になるのか確かめましょう:
# fn main() {} pub fn greeting(name: &str) -> String { String::from("Hello!") }
このテストを実行すると、以下のように出力されます:
running 1 test
test tests::greeting_contains_name ... FAILED
failures:
---- tests::greeting_contains_name stdout ----
thread 'tests::greeting_contains_name' panicked at 'assertion failed:
result.contains("Carol")', src/lib.rs:12:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
tests::greeting_contains_name
この結果は、アサーションが失敗し、どの行にアサーションがあるかを示しているだけです。
より有用な失敗メッセージは今回の場合、greeting
関数から得た値を出力することでしょう。
greeting
関数から得た実際の値で埋められるプレースホルダーを含むフォーマット文字列からなるカスタムの失敗メッセージを与え、
テスト関数を変更しましょう:
#[test]
fn greeting_contains_name() {
let result = greeting("Carol");
assert!(
result.contains("Carol"),
//挨拶は名前を含んでいません。値は`{}`でした
"Greeting did not contain name, value was `{}`", result
);
}
これでテストを実行したら、より有益なエラーメッセージが得られるでしょう:
---- tests::greeting_contains_name stdout ----
thread 'tests::greeting_contains_name' panicked at 'Greeting did not
contain name, value was `Hello!`', src/lib.rs:12:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
実際に得られた値がテスト出力に見られ、起こると想定していたものではなく、 起こったものをデバッグするのに役に立ちます。
should_panic
でパニックを確認する
期待する正しい値をコードが返すことを確認することに加えて、想定通りにコードがエラー状態を扱っていることを確認するのも重要です。
例えば、第9章のリスト9-9で生成したGuess
型を考えてください。Guess
を使用する他のコードは、
Guess
のインスタンスは1から100の範囲の値しか含まないという保証に依存しています。
その範囲外の値でGuess
インスタンスを生成しようとするとパニックすることを確認するテストを書くことができます。
これは、テスト関数にshould_panic
という別の属性を追加することで達成できます。
この属性は、関数内のコードがパニックしたら、テストを通過させます。つまり、
関数内のコードがパニックしなかったら、テストは失敗するわけです。
リスト11-8は、予想した時にGuess::new
のエラー条件が発生していることを確認するテストを示しています。
ファイル名: src/lib.rs
# fn main() {} pub struct Guess { value: u32, } impl Guess { pub fn new(value: u32) -> Guess { if value < 1 || value > 100 { //予想値は1から100の間でなければなりません panic!("Guess value must be between 1 and 100, got {}.", value); } Guess { value } } } #[cfg(test)] mod tests { use super::*; #[test] #[should_panic] fn greater_than_100() { Guess::new(200); } }
#[test]
属性の後、適用するテスト関数の前に#[should_panic]
属性を配置しています。
このテストが通るときの結果を見ましょう:
running 1 test
test tests::greater_than_100 ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
よさそうですね!では、値が100より大きいときにnew
関数がパニックするという条件を除去することでコードにバグを導入しましょう:
# fn main() {} # pub struct Guess { # value: u32, # } # // --snip-- impl Guess { pub fn new(value: u32) -> Guess { if value < 1 { panic!("Guess value must be between 1 and 100, got {}.", value); } Guess { value } } }
リスト11-8のテストを実行すると、失敗するでしょう:
running 1 test
test tests::greater_than_100 ... FAILED
failures:
failures:
tests::greater_than_100
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
この場合、それほど役に立つメッセージは得られませんが、テスト関数に目を向ければ、
#[should_panic]
で注釈されていることがわかります。得られた失敗は、
テスト関数のコードがパニックを引き起こさなかったことを意味するのです。
should_panic
を使用するテストは不正確なこともあります。なぜなら、コードが何らかのパニックを起こしたことしか示さないからです。
should_panic
のテストは、起きると想定していたもの以外の理由でテストがパニックしても通ってしまうのです。
should_panic
のテストの正確を期すために、should_panic
属性の省略可能なexpected
引数を追加できます。
このテストの拘束具が、失敗メッセージに与えられたテキストが含まれていることを確かめてくれるでしょう。
例えば、リスト11-9のGuess
の変更されたコードを考えてください。ここでは、
new
関数は、値の大小によって異なるメッセージでパニックします。
ファイル名: src/lib.rs
# fn main() {} # pub struct Guess { # value: u32, # } # // --snip-- impl Guess { pub fn new(value: u32) -> Guess { if value < 1 { //予想値は、1以上でなければなりませんが、{}でした panic!("Guess value must be greater than or equal to 1, got {}.", value); } else if value > 100 { //予想値は100以下でなければなりませんが、{}でした panic!("Guess value must be less than or equal to 100, got {}.", value); } Guess { value } } } #[cfg(test)] mod tests { use super::*; #[test] // 予想値は100以下でなければなりません #[should_panic(expected = "Guess value must be less than or equal to 100")] fn greater_than_100() { Guess::new(200); } }
should_panic
属性のexpected
引数に置いた値がGuess::new
関数がパニックしたメッセージの一部になっているので、
このテストは通ります。予想されるパニックメッセージ全体を指定することもでき、今回の場合、
Guess value must be less than or equal to 100, got 200.
となります。
should_panic
の予想される引数に指定すると決めたものは、パニックメッセージの固有性や活動性、
テストの正確性によります。今回の場合、パニックメッセージの一部でも、テスト関数内のコードが、
else if value > 100
ケースを実行していると確認するのに事足りるのです。
expected
メッセージありのshould_panic
テストが失敗すると何が起きるのが確かめるために、
if value < 1
とelse if value > 100
ブロックの本体を入れ替えることで再度コードにバグを仕込みましょう:
if value < 1 {
panic!("Guess value must be less than or equal to 100, got {}.", value);
} else if value > 100 {
panic!("Guess value must be greater than or equal to 1, got {}.", value);
}
should_panic
テストを実行すると、今回は失敗するでしょう:
running 1 test
test tests::greater_than_100 ... FAILED
failures:
---- tests::greater_than_100 stdout ----
thread 'tests::greater_than_100' panicked at 'Guess value must be
greater than or equal to 1, got 200.', src/lib.rs:11:12
note: Run with `RUST_BACKTRACE=1` for a backtrace.
note: Panic did not include expected string 'Guess value must be less than or
equal to 100'
(注釈: パニックには'Guess value must be less than or equal to 100'という予想される文字列が含まれませんでした)
failures:
tests::greater_than_100
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
この失敗メッセージは、このテストが確かにまさしく予想通りパニックしたことを示唆していますが、
パニックメッセージは、予想される文字列の'Guess value must be less than or equal to 100'
を含んでいませんでした。
実際に得られたパニックメッセージは今回の場合、Guess value must be greater than or equal to 1, got 200
でした。
そうしてバグの所在地を割り出し始めることができるわけです!
今やテスト記法を複数知ったので、テストを走らせる際に起きていることに目を向け、
cargo test
で使用できるいろんなオプションを探究しましょう。