Skip to content

テストダブルの種類

This content is a draft and will not be included in production builds.

プログラムのテストに用いられる、本物の代わりに使われるオブジェクトをテストダブル(test double)と呼ぶ。

xUnit Test PatternsのTest Doubleパターン1によると、テストダブルは、その機能によって分類できる。前提としてテスト対象への入出力は2つある。

  • 間接入力: テストコードからは見えないテスト対象への入力
  • 間接出力: テストコードからは見えないテスト対象からの出力

テスト対象が間接出力を与えて、結果として間接入力を得る場合もある。

テスト結果に何も作用しないテストダブルを特別にダミーと呼ぶ。例えば型の埋め合わせをするだけのオブジェクトがダミーに該当する。テスト対象はダミーから以下の作用を得る。

  • 間接入力: なし
  • 間接出力: なし

テストダブルを使わないかどうかはテスト対象の実装によるので、明確に区別する理由はあまりないと思う。

func Encoder interface {
Encode(p []byte) error
}
// Encoderを使っていない
func handleIndex(w http.ResponseWriter, _ Encoder)
type DummyEncoder struct {}
func (*DummyEncoder) Encode(_ []byte) error {
return nil
}
func TestHandleIndex(t *testing.T) {
w := httptest.NewRecorder()
handleIndex(w, &DummyEncoder{})
}

使っていたら何になるのか?

テスト対象へ間接入力を与えるテストダブルをスタブと呼ぶ。例えば現在時刻を返す関数(time.Now)等がスタブに該当する。テスト対象はスタブから以下の作用を得る。

  • 間接入力: あり
  • 間接出力: なし
func handleIndex(w http.ResponseWriter, nowFunc func())
func TestHandleIndex(t *testing.T) {
w := httptest.NewRecorder()
handleIndex(w, func() {
return time.Date(2024, time.April, 1, 0, 0, 0, 0, time.UTC)
})
}

テスト対象からの間接出力を受けて、テストコードが間接出力を参照するテストダブルをスパイと呼ぶ。例えばログを記録するロガー等がスパイに該当する。テスト対象はスパイから以下の作用を得る。

  • 間接入力: なし
  • 間接出力: あり

重要なのはテストコードが間接出力を参照するところで、ただ間接出力を受けるだけならスパイではない。

テスト対象からの間接出力を受けて、モック自身が成功/失敗を判定するテストダブルをモックと呼ぶ。テスト対象はモックから以下の作用を得る。

  • 間接入力: なし
  • 間接出力: あり

スパイとの違いは検証機能を持つかどうか。例えばC#のMoqVerifyメソッドを持っていて、モック側でテストダブルが正しく呼ばれたかどうかの検証を行う。

テスト中でも本物と同じように動作するテストダブルをフェイクと呼ぶ。これは間接入出力の向きによらないが、更新を反映したうえで返すものでなければ固定値(スタブ)で良いのだから、ほとんどの場合はどちらも受け取る。

  • 間接入力: なし
  • 間接出力: あり
  1. https://twitter.com/t_wada/status/608573127879069696