Rustのプロジェクトにおいて、テストコードは主に以下の二つの形式で記述される。
1. ソースファイル内でのモジュール化されたテスト
関数ごとの単体テストを行う場合、実装と同じファイル内に #[cfg(test)] 属性付きのモジュールとして記述することが一般的である。このモジュールでは、親スコープから必要な要素をインポートして利用する。
// src/main.rs
pub fn calculate_sum(x: i32, y: i32) -> i32 {
x + y
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[test]
fn verify_calculate_sum() {
assert_eq!(calculate_sum(4, 5), 9);
}
}
2. 独立したテストファイルによる統合テスト
ライブラリクレートや大規模なアプリケーションでは、tests ディレクトリ配下に個別のテストファイルを作成し、それらを使って統合レベルのテストを構築するのが適切である。これらのテストは公開されたAPIを使用して動作確認を行う。
my_project/
├── src/
│ ├── lib.rs
│ └── main.rs
└── tests/
└── api_tests.rs
tests/api_tests.rs:
use my_project::calculate_sum;
#[test]
fn integration_check() {
assert_eq!(calculate_sum(10, 20), 30);
}
main.rs内の関数に対するテストの書き方
- 関数の可視性を変更する: テスト対象となる関数が
main.rs内にある場合は、pubキーワードを付けて外部からアクセス可能にする必要がある。 - 同一ファイル内でのテスト記述: 上記のように、
main.rs内部にテストモジュールを設置することで、直接テストを実行できる。 - ロジックの分離によるテスト容易性向上: 実際の処理部分を
lib.rsへ移動させることで、より自然にテスト可能な設計となる。main.rsはエントリポイントとして、その機能を呼び出すだけにするのが望ましい。
再構成後のディレクトリ構造:
src/
├── lib.rs
└── main.rs
src/lib.rs:
pub fn perform_addition(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod internal_checks {
use super::*;
#[test]
fn addition_works() {
assert_eq!(perform_addition(7, 8), 15);
}
}
src/main.rs:
use my_project::perform_addition;
fn main() {
let output = perform_addition(6, 4);
println!("計算結果: {}", output);
}