新しいテストの追加
一般に、rustc のバグを修正するすべての PR には、何らかの回帰テストが
付随していることを期待しています。 このテストは main では失敗し、PR 後には
成功する必要があります。
これらのテストは、過去の過ちを繰り返さないようにするために
非常に役立ちます。
最初に決めるべきことは、どの種類のテストを追加するかです。 これは変更の性質と、何を検証したいかによって決まります。 大まかなガイドラインをいくつか示します。
- コンパイラーテストの大半は compiletest で行われます。
- 標準ライブラリへの変更は、通常、標準ライブラリ内でテストされます。
- 標準ライブラリのテストの大半は、典型的な API の挙動を例示し検証する doctest として書かれます。
- 追加のユニットテストは
library/${crate}/testsに置く必要があります(${crate}は通常stdです)。 allocまたはcoreクレートのテストは、それぞれ別のクレートalloctestsまたはcoretestsに置かなければなりません。- NOTE: 不安定な機能のユニットテストを追加する場合、
#![feature(...)]宣言はlibrary/${crate}tests/lib.rsではなくlibrary/${crate}tests/tests/lib.rsに追加しなければなりません。
- NOTE: 不安定な機能のユニットテストを追加する場合、
- コードが独立したシステムの一部であり、コンパイラー出力をテストしていない場合は、 ユニットテストまたは統合テストの使用を検討してください。
- rustdoc を実行する必要がありますか?
rustdocまたはrustdoc-uiテストを優先してください。 場合によってはrustdoc-jsも必要になります。 - その他の compiletest テストスイートは、一般に特別な目的で使用されます。
- gdb または lldb を実行する必要がありますか?
debuginfoテストスイートを使用してください。 - LLVM IR または MIR IR を調べる必要がありますか?
codegenまたはmir-optテストスイートを使用してください。 - 生成されたバイナリを何らかの方法で調べる必要がありますか?
あるいは他のすべてのテストスイートでは目的に対して制限が強すぎますか?
その場合は
run-makeを使用してください。- ツリー内の
rustcと組み合わせてツリー内のcargoを検証する必要がある場合は、run-make-cargoを使用してください。
- ツリー内の
- より専門的なテストスイートについては、compiletest の章を参照してください。
- gdb または lldb を実行する必要がありますか?
追加するテストの種類を決めたら、長期にわたって扱いやすいテストを作成する方法について、 ベストプラクティスを参照してください (つまり、数年後にテストが失敗したり変更が必要になったりした場合に、 どうすれば作業を容易にできるか、ということです)。
UI テストの手順
以下は、最も一般的なコンパイラーテストの 1 つである UI テストを作成するための基本的なガイドです。 このチュートリアルでは、async のエラーメッセージ用のテストを追加します。
ステップ 1: テストファイルを追加する
最初のステップは、tests/ui ツリー内のどこかに Rust ソースファイルを
作成することです。
テストを作成するときは、適切な場所と名前を見つけるよう最善を尽くしてください
(詳細はテストの整理を参照)。
命名は開発で最も難しい部分なので、
ここから先はすべて楽になるはずです!
async テストを tests/ui/async-await/await-without-async.rs に置きましょう。
// ユーザーが非`async`関数内で`await`を書いたときに診断を提供する。
//@ edition:2018
async fn foo() {}
fn bar() {
foo().await
}
fn main() {}
このテストについて注目すべき点がいくつかあります。
- 先頭は、テストの目的を説明する短いコメントで 始める必要があります。
//@ edition:2018コメントはディレクティブと呼ばれ、 テストをどのようにビルドするかについて compiletest に指示を提供します。 ここでは、asyncが動作するようにエディションを 設定する必要があります(デフォルトは 2015 エディションです)。- その後にテストのソースが続きます。 簡潔で要点を押さえたものにするようにしてください。 バグ報告から例を最小化しようとしている場合は、 ある程度の労力が必要になることがあります。
- このテストは空の
fn main関数で終えています。 これは、UI テストのデフォルトがbinクレートタイプであり、テストに「main not found」エラーを 出したくないためです。 代わりに、#![crate_type="lib"]を追加することもできます。
ステップ 2: 期待される出力を生成する
次のステップは、コンパイラーから期待される出力スナップショットを作成することです。
これは --bless オプションで行えます。
./x test tests/ui/async-await/await-without-async.rs --bless
これにより、コンパイラーがビルドされ(まだビルドされていない場合)、
テストがコンパイルされ、コンパイラーの出力が
tests/ui/async-await/await-without-async.stderr というファイルに配置されます。
しかし、このステップは失敗します! 次のようなエラーメッセージが表示されるはずです。
error: /rust/tests/ui/async-await/await-without-async.rs:7: unexpected error: ‘7:10: 7:16:
awaitis only allowed insideasyncfunctions and blocks E0728’
これは、stderr にソースファイル内のエラーアノテーションと一致しないエラーが 含まれているためです。
ステップ 3: エラーアノテーションを追加する
すべてのエラーには、エラーのテキストを含むコメントでソース内に アノテーションを付ける必要があります。 この場合、次のコメントをテストファイルに追加できます。
fn bar() {
foo().await
//~^ ERROR `await`は`async`関数およびブロック内でのみ許可されています
}
//~^ の波線キャレットコメントは、そのエラーが
前の行に属していることを compiletest に伝えます
(詳細はエラーアノテーションセクションを参照)。
保存して、もう一度テストを実行します。
./x test tests/ui/async-await/await-without-async.rs
これで成功するはずです。やった!
ステップ 4: 出力を確認する
前のステップとある程度並行して、作成された .stderr ファイルを確認し、
期待どおりに見えるかを調べる必要があります。
新しい診断メッセージを追加している場合は、
メッセージ全体がどれだけ読みやすく見えるか、
特に Rust に慣れていない人にとってどうかも考えるよい機会です。
例の tests/ui/async-await/await-without-async.stderr ファイルは
次のようになります。
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/await-without-async.rs:7:10
|
LL | fn bar() {
| --- this is not `async`
LL | foo().await
| ^^^^^^ only allowed inside `async` functions and blocks
error: aborting due to previous error
For more information about this error, try `rustc --explain E0728`.
通常のコンパイラー出力とは少し異なって見える点があることに 気づくかもしれません。
$DIRは、システム間で異なるパス情報を取り除きます。LL値は行番号を置き換えます。 これにより、ソース内の小さな変更が大きな差分を引き起こすことを避けられます。 詳細は正規化セクションを参照してください。
この段階では、最後のいくつかのステップを何度か繰り返して、 テストを調整し、テストを再 bless し、出力を再確認する必要があるかもしれません。
ステップ 5: 他のテストを確認する
診断メッセージを追加または変更すると、テストスイート内の他のテストに 影響することがあります。 PR を投稿する前の最後のステップは、他に影響を与えていないかを 確認することです。 通常は UI スイートを実行するのが良い出発点です。
./x test tests/ui
他のテストが失敗し始めた場合、何が変更されたのか、そして 新しい出力が妥当かどうかを調査する必要があるかもしれません。
また、--bless フラグを使って出力を再承認する必要があるかもしれません。
テストの内容を説明するコメント
テストファイルの最初のコメントは、テストの要点を要約し、 そのテストで何が重要なのかを強調するべきです。 そのテストに関連する issue 番号がある場合は、その issue 番号を含めてください。
このコメントは、それほど詳しくする必要はありません。 次のようなものだけでも十分な場合があります: 「#18060 の回帰テスト: match アームが誤った順序でマッチしていた」。
これらのコメントは、後であなたのテストが壊れたときに、他の人にとって非常に役立ちます。なぜなら、 問題が何であるかを強調できることが多いからです。 また、何らかの 理由でテストをリファクタリングする必要がある場合にも役立ちます。なぜなら、そのテストのどの部分が 重要だったのかを他の人に知らせてくれるからです。 多くの場合、テストは本来テストするはずだったことを もはやテストしなくなったために書き直さなければならず、その場合、そのテストが正確に何をテストする はずだったのかを知ることが役立ちます。