🦁

Test Double(stub, spy, mock, fake, dummy)について理解する

に公開

TestDoubleとは

自動テストに使用する偽物、代用品。
たとえば、データベースや外部サービスの動作を模倣した偽物(テストダブル)を作り、自動テストで使う。
TestDoubleの意味でモックという言葉が使われることがあるが、定義上モックはTestDoubleの一部。
モック(Mock)、スタブ(Stub)、フェイク(Fake)、スパイ(Spy)、ダミー(Dummy)がある。
用途はそれぞれの項目に記載。また、Test Doubleを使う目的の一つに、疎結合なテストの実現があル。

SUTとは

System Under Testでテスト対象のシステム(オブジェクト)

DOCとは

depended-on component
SUTが依存する、個々のクラスまたは大きな粒度のコンポーネント
これをTest Doubleに差し替える

Test Stubとは


主な役割は、SUTへの間接入力を制御すること。
SUTからメソッドが呼び出されたときに、あらかじめ設定しておいた特定の値を返すように作られる

何のために使われる?

テスト中に呼び出された際に事前に用意された応答(値や例外)を提供する。
SUTに特定の間接入力を供給し、SUTを特定のパスに進ませたり、テスト環境で利用できないソフトウェアの部分を回避したりするための制御点として使用される。
間接出力の検証には使用されない。

テスト環境で利用できないソフトウェアの部分を回避する具体例

実際の依存コンポーネントは、テストを実行する上で問題となる場合がある

  • まだ利用できない(開発中など)
  • テストに必要な特定の結果を返さない (例: 特定のエラーコードや、特定のタイミングでの応答)
  • 望ましくない副作用がある (例: 実際のデータベースへの書き込み、メール送信、外部システムへの接続)
  • 実行に時間がかかりすぎる (例: ネットワーク通信、ディスクI/O)

Test Spyとは


SUTの間接出力を記録するために用いられる。
SUTからの間接出力を記録し、テストメソッド側でアサーションを行い検証する

MockではなくSpyを使う時

  • 事前に期待値が予測できない時(sutが生成するデータやsutの状態によって挙動が変わるなど)
  • テストで何を検証しているのかを分かりやすく、意図を明確にしたいとき
  • Mock Object生成ツールを使っているが、そのツールが提供するAssertion Methodsをカスタマイズできない
  • Mock Objectのアサーション失敗がTest Runnerに正しく伝わらないとき

Mock Objectとは


間接出力に対する振る舞い検証 (Behavior Verification) を行う
事前に期待値を設定し、SUTからのメソッド呼び出しを受けるたびに、期待値と即座に比較する。期待と異なる呼び出しがあった場合、その場でモック側でアサーションを実行し、テストを失敗させる。
すべてのSUTの実行が完了した後、テストコード側からverifyなどの関数を呼び出し、最終検証も行う。
SUTの実行中にのみアクセス可能な値でアサーションを行いたいはSpyではできないのでMockで行う

Fake Objectとは


DOCの機能を、本物より大幅に簡易化し、軽量に実装したもの。
実際のデータベースの代わりにインメモリデータベースをFake Objectとして使用するケースなど。
制御点としても観測点としても使用されない。

使用する一般的な理由

  • 実際の依存コンポーネントがまだ利用できない
  • 遅すぎる
  • 有害な副作用のためにテスト環境で使用できない

Dummy Objectとは

主にSUT が呼び出すメソッドのパラメータリストを埋めるために用いられる。
テスト中に実際に使用されることがないが、引数で必要なケース。
使用されないので、機能的な実装を一切持たなくても良い。

Dummy Objectを利用する例

Departmentオブジェクトを用いたServiceのテストをするとき、Departmentのインスタンス化にmenberが必要。
しかしmemberはSUTでは利用しない。この時memberにdummyを用いる

参考文献

定義には諸説あると思いますが主に下記を参照しています。
http://xunitpatterns.com/Test Double Patterns.html
https://martinfowler.com/articles/mocksArentStubs.html

ご指摘などありましたらコメントにてお願いします!

Discussion