空想犬猫記

※当日記では、犬も猫も空想も扱っておりません。(旧・エト記)

Rust独学メモ3

テストの書き方

Unit テストと Integration テストで、書く場所が異なる

We create a tests directory at the top level of our project directory, next to src. Cargo knows to look for integration test files in this directory. We can then make as many test files as we want, and Cargo will compile each of the files as an individual crate.

  • Unit テストはモジュール内に、#[cfg(test)] というアノテーションを付けたモジュールを作成する
    • Unit テスト用のモジュールからは、publish されていない private なメンバにもアクセスできる
    • 関数に #[test] アノテーションを付けておくと test runner にピックアップされて実行される
  • Integration テストは src ディレクトリの並びの tests ディレクトリに、.rs ファイル(=クレート・ルート)を作成する

Integration テストのサブモジュールを .rs 形式で作ると、クレートとしても、サブモジュールとしても参照されそうだなーというのが第一感。それの疑問に対する回答は

Having common appear in the test results with running 0 tests displayed for it is not what we wanted. We just wanted to share some code with the other integration test files.

To avoid having common appear in the test output, instead of creating tests/common.rs, we’ll create tests/common/mod.rs.

まさかのノーガード戦法だった。しかもここだけなぜ「running 0 tests」が出てしまうのかの説明を省いてリンクを張ってお茶を濁していて誠意を感じない。クレートとモジュールの恣意的な扱い(おそらくコンパイラの実装の都合)のしわ寄せがここに来て、足の小指をぶつけてる。要は運用で回避してねという方針。結論:クレートとしても、サブモジュールとしても参照される。そして、インテグレーションテスト用の .rs ファイルで書かれたサブモジュールは、サブモジュールを利用する .rs ファイルの数の回数分、再コンパイルされてしまう。これは、設計者からしたら誤用の範囲であると思うが、サブモジュールとして利用された .rs ファイルに書かれたテストは、サブモジュールとしてインポートされた回数と、自分自身がクレートとしてコンパイルされた+1回だけ実行される。インテグレーションテストを書いていて、とあるファイルに書いたユーティリティをインポートして使うというのは、やりがちなことなので、意外と侮れない落とし穴だと思う。例えば、ひとつのファイルにユーティリティとテストを書き溜めて、サイズが大きくなってきたので、新しいファイルを追加して、元のファイルをインポートしてヨシ!続きを書くぞー…なんてことをすると、一気に流れるテストの数が2倍になるわけである。

知らなくてハマったら発狂しそうな仕様である。

Rust独学メモ - 空想犬猫記 できっちりとクレートはコンパイル単位、ファイルはモジュール、コンパイラに最初に渡されるファイルがクレート・ルートで、それがクレートのルートモジュールになり、以下芋づる式にサブモジュールがコンパイルされていく、という理解を固めて置かないとかなり置いてきぼりになりそう。現実的な解決策を出している点では文句の付けようは無いのだけれど。