モック

モックには、Mockall という広く使われているライブラリがあります。コードを トレイトを使うようにリファクタリングする必要があります。そうすれば、それらを すばやくモック化できます。

// 著作権 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0

use std::time::Duration;

#[mockall::automock]
pub trait Pet {
    fn is_hungry(&self, since_last_meal: Duration) -> bool;
}

#[test]
fn test_robot_dog() {
    let mut mock_dog = MockPet::new();
    mock_dog.expect_is_hungry().return_const(true);
    assert!(mock_dog.is_hungry(Duration::from_secs(10)));
}
  • Mockall は Android(AOSP)で推奨されているモックライブラリです。ほかにも crates.io で利用可能なモックライブラリ があり、特に HTTP サービスのモックの分野では多く使われています。ほかの モックライブラリも Mockall と似た仕組みで動作し、特定のトレイトの モック実装を簡単に取得できます。

  • モックはやや 議論のあるもの である点に注意してください。モックを使うと、 テストをその依存関係から完全に分離できます。直接的な結果として、テストの 実行はより高速かつ安定します。一方で、モックが誤って設定され、実際の 依存関係が返す結果とは異なる出力を返すことがあります。

    可能であれば、実際の依存関係を使うことを推奨します。たとえば、多くの データベースではインメモリバックエンドを設定できます。これにより、テストで 正しい振る舞いを得られるうえ、高速で、後始末も自動的に行われます。

    同様に、多くの Web フレームワークでは、localhost 上のランダムなポートに バインドするインプロセスサーバーを起動できます。コードを実際の環境で テストするのに役立つため、フレームワークをモック化して済ませるよりも、 常にこちらを優先してください。

  • Mockall は Rust Playground には含まれていないため、この例はローカル環境で 実行する必要があります。cargo add mockall を使うと、既存の Cargo プロジェクトに Mockall をすばやく追加できます。

  • Mockall には豊富な機能があります。特に、渡された引数に依存する期待条件を 設定できます。ここではこれを使って、最後に餌を与えてから 3 時間後に空腹に なる猫をモックします。

// 著作権 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0

#[test]
fn test_robot_cat() {
    let mut mock_cat = MockPet::new();
    mock_cat
        .expect_is_hungry()
        .with(mockall::predicate::gt(Duration::from_secs(3 * 3600)))
        .return_const(true);
    mock_cat.expect_is_hungry().return_const(false);
    assert!(mock_cat.is_hungry(Duration::from_secs(5 * 3600)));
    assert!(!mock_cat.is_hungry(Duration::from_secs(5)));
}
  • .times(n) を使うと、モックメソッドが呼び出される回数を n 回に 制限できます — これが満たされない場合、モックは破棄時に自動的に panic します。