Mocks Aren’t Stubs をよむ

RSpecのテストで Mock なんとかでエラーをはいているのを見つけてちょっと調べたところ、徐々に深そうなところにはいってきた。
そういえば、WEwLCも途中までしか読んでいないことを思い出す。

Mocks Aren't Stubs 有名なマーチン・ファウラーがモックとスタブについて説明した有名な文書とのこと。

以下、つまみ訳というかメモというか。

  • The Difference Between Mocks and Stubs (モックとスタブの違い)
    • Gerard Meszarosの本で定義されている
    • Test Doubles: 偽装オブジェクトを使ったテストの総称
      • Dummy objects: ダミーオブジェクトはテストにはパスするが、実際に使われることがないオブジェクト。ふつうはパラメータリストを埋めるのにつかわれる
      • Fake objects: フェイクオブジェクトは実際に動作可能な実装が書かれている。しかし本番で使うにはよろしくない手抜きをしてある(たとえば、インメモリで動くデータベース)
      • Stubs: スタブは、テスト中の呼び出しに決まった応答(canned answer)を返す。ふつうはテストでプログラムされていない呼び出しには一切答えない。スタブは呼び出しの情報を記録することもある。例えば、電子メールゲートウェイのスタブは、すべての送信済みメッセージを記録、または送信数だけを記録していたりする。
      • Mocks: モックはここで説明する。呼び出しと、期待される応答の仕様に基づいて、先行実装された(pre-programmed)オブジェクトだ。
  • Classical and Mockist Testing: 古典的テストとMockistのテスト
    • classical TDD: 古典的なTDD(テスト駆動開発)はできる限りリアルオブジェクトを使い、使えない場合は偽装を使う。...以下略
    • mockist TDD: あらゆるオブジェクトに関してもモックを使う。
    • mockst TDDから派生したのがBDD(ビヘイビア駆動開発)だ。BDDは同僚のDan NorthがTDDを学ぶことを助けるために考えたテクニックで、TDDをデザインテクニックとして使うことに注目している。テストをビヘイビアに読み替えることで、TDDを使って「オブジェクトが何をしたいのか」を考えやすくなる。BDDはmockistのアプローチを使うが、ネーミングスタイルや分析を取り込んで拡張している。
  • Fixture Setup(フィクスチャのセットアップ)
    • 古典的TDDでは、協調して動くオブジェクト全体のSUTを用意しなければいけない。テスト対象が数オブジェクトしかない場合でも、SUTは大量になることもある
    • MockistTDDはオブジェクトの隣接するオブジェクトのモックが必要なだけ。
  • Test Isolation: テストの独立性
    • バグがあるとテストが失敗する
      • 古典的なテストは、複数のオブジェクトでテストするので、よく使われるオブジェクトにバグがあると、いろんな場所でテスト失敗になる。テスト失敗が、問題の根源を示していない。
      • Mockistのテストはどのオブジェクトで失敗したかわかるので、ソースに到達しやすい。
    • 古典的なテストは、ユニットテストであり、かつ、ミニ結合テストになっている。複数のオブジェクト間の相互作用もテストしている。Mockistテストは、この部分は捨てている。
    • どっちの方法をとるにせよ、システム全般の受け入れテストはしなければならない。
  • Coupling Tests to Implementations: テストと実装の組み合わせ
    • 古典的テストは最終的に問題ないかをテストする
    • Mockistはオブジェクトが正しく利用者(オブジェクト)と会話できているかをテストする。実装と対になっている。
  • Design Style: デザイン・スタイル
    • Mockistは Outside-in のアプローチ。古典的テスト派は domain model out。
    • Mockistはメソッドチェーンを避ける。
    • オブジェクト指向で理解が難しい原則に "Tell Don't Ask" がある。getterを避ける。MockistいわくMockistテストはこれを助ける。古典的テスト派は他の方法でやっている
    • こういったデザインスタイルの違いが、MockistがMockist TDDを採用する理由になっている
  • So should I be a classicist or a mockist?
    • 私は古典的なテストをやってきたし、それを変えるほどの理由は見つけていない。
    • 古典的テストの立場に立って、公平に議論をしていきたい
    • Mockistのテストが良さそうに思えたら、試してみてほしい。以下の2つの領域で問題があるようなら、解決に役立つはずだ
      • テストが失敗してから、問題がどこにあるのかを見つけるまでに時間がかかっている
      • 十分なビヘイビアが定義されていない
  • Final Thought: おわりに
    • ユニットテスト、xUnit、TDDへの関心が高まっていて、モックオブジェクトを使う人が増えている。mockist/古典的の違いを知らないで、モックオブジェクトを学ぶには多くの時間が必要になる。
    • Mockistになる必要を感じなくても、多くのソフトウェアのデザイン乗の選択を学ぶことは有用だ
    • この文書の目的は2つの方法の違いとトレードオフを明らかにすること。