Test Double のタイプ達


Test Double とは

映画などで、危険なシーンや高度なスタントに使用されるスタントパフォーマーを「スタントダブル」、肉体的に難しいダンスを披露する「ダンスダブル」などと呼びます。 より一般的には、あるシーンを出演者が演じることができない場合に、替え玉となって演技をする俳優を「ボディダブル」(body double)といいます。

システム開発の分野では、テスト時に、このような替え玉となるものを総称して「テストダブル」(Test Double)と呼びます。 テストダブルは、コラボレーターの代わりにテストで使用される任意のオブジェクトです。


Test Double のタイプ

テストダブルには標準となる仕様は存在しませんが、Gerard Meszaros は、テストダブルのタイプとして次の5つを挙げています。

タイプ 説明
ダミー(Dummy) テストを実行するために必要だが、テスト対象としては無関係なもの。例えば、メソッドの引数として必要だが、テストではその引数を利用しない場合に渡すオブジェクト
スタブ(Stub) テスト対象に「間接的入力(indirect inputs)」を提供する。例えば、インターフェースの実装として、戻り値がvoidのメソッドは空実装、値を返却するメソッドは単に固定値を返すようなものを用意して、テストで利用する
スパイ(Spy) テスト対象から外部への「間接出力(indirect outputs)」を確認する。スタブの機能に加え、スタブのメソッドの呼び出し回数や呼び出し方法を記録し、テストコードの呼び出しの後で、その内容を検証することができる
モック(Mock) テスト対象から外部への「間接出力(indirect outputs)」を検証する。テストコードの呼び出し前に期待する結果を設定しておき、テスト実行時にオブジェクト内部で検証が行われる
フェイク(Fake) テスト対象から利用する、本物のコンポーネントと同等の挙動を行うオブジェクト。これ自体には(モックに有るような)検証の振る舞いは含まず、多くの場合実際のオブジェクトに近い働きをするが、より単純な実装となる。テスト時に利用するインメモリデータベースがその例となる

テストダブルは、上記のタイプに明確に分類できない場合がほとんどです。

モックライブラリの提供するオブジェクトは、スタブとして動作し、スパイとモックの機能を合わせて提供しますし、スタブとフェイクの明確な境界線が存在するわかではありません。


ダミー(Dummy)

テストを実行するために必要だが、テスト対象に対するテスト観点からは無関係なもので、通常これらはパラメーターのリストを埋めるためだけに使用されます。

テスト対象のメソッドを実行する際に、テスト自体には無関係で意味を成さないが、引数として何らかのオブジェクトが必要、といったケースでダミーオブジェクトを用意してテストを実行します。 文字列の非nullの引数が必要だが、テストとしてはどのような文字列でも関係無いため、"dummy" という文字列を渡したり、引数のオブジェクトを単に継承したダミーオブジェクトを用意するといったケースで使います。

厳密にはテストダブルの一種では無いとされることもあります。


スタブ(Stub)

テスト対象に「間接的入力(indirect inputs)」を提供します。 つまりテスト対象は、スタブから何かしらの入力を受け取り、その入力によりテストを進めます。

スタブオブジェクトとしてインターフェースを実装し、戻り値がvoidのメソッドは空実装、値を返却するメソッドは単に定型のレスポンスを返すようにしてテストで利用します。 通常は、テスト用にプログラムされたもの以外にはまったく応答しません。


スパイ(Spy)

スタブの挙動に加え、スパイではテスト対象から外部への「間接アウトプット(indirect outputs)」を記録します。 例えば、スタブオブジェクトでは、戻り値がvoidのメソッドは空実装としますが、スパイオブジェクトでは、そのメソッドの呼び出しを記録します。 記録した内容は、テストメソッドの実行後にその内容を取り出すことで、メソッドの呼び出しが期待通りに行われていたかどうかを確認することができます。

スパイは、テスト時のインタラクション(メソッド呼び出し)を記録できるスタブであると言うことができます。


モック(Mock)

モックは、テスト対象から外部への「間接アウトプット(indirect outputs)」を検証します。 テストコードの呼び出し前に、モックオブジェクトに対して期待する挙動を定義しておくことで、テスト実行時にモックオブジェクト自身がその内容を検証します。

予期しない呼び出しが行われていないか、予期していたすべての呼び出しが行われたかを検証することができるスタブ(またはスパイ)であると言えます。

モックオブジェクトは、テストスタブやテストスパイの機能を含む、より広義のオブジェクトになります。


フェイク(Fake)

テスト対象から利用する、本物のコンポーネントと同等の挙動を行うオブジェクトで、多くの異なるシナリオで使用できる実装を提供します。 これ自体には(モックに有るような)検証の振る舞いは含まず、多くの場合実際のオブジェクトに近い働きをします。

本物のコンポーネントを使った場合の副作用が問題となる場合や、テストの実行時間短縮のために、本物相当であるが、より簡素な実装のオブジェクトで代用するケースで利用されます。 典型的には、H2 データベースなどをインメモリモードでテスト時に利用するといったケースが該当します。

スパイやモックにあるようなインタラクションの記録などは行わず、実オブジェクトの振る舞いのみを提供します。 スタブでは特定のテストに特化した半実装のみを提供するのに対し、フェイクでは実際のオブジェクトに近い動きを提供します。


Test Double のタイプの比較

以上の各種 Test Double のタイプを比較すれば、以下のようになります。

タイプ 間接入力の提供 間接出力の記録 間接出力の検証
ダミー(Dummy) × × ×
スタブ(Stub) × ×
スパイ(Spy) ×
モック(Mock)
フェイク(Fake) × ×
  • 間接入力:テスト対象メソッド内で、テストダブルが返却する戻り値を利用する(テストダブルのメソッド呼び出しによりテストで利用する戻り値を提供する)
  • 間接出力:テスト対象メソッド内から、テストダブルのメソッドを特定の引数を伴って行われる呼び出し