RSpecでモックとスタブ

きちんと理解してなかったのでいろんなページを参考にいじくりまわしてみた。
そのメモ。

モックとはスタブとは

Martin Fowler’s Bliki in Japanese – TestDoubleの定義がわかりやすいので引用。


スタブは、テスト時の呼び出しに対して、あらかじめ用意された結果を返す。
通常、テスト用にプログラムされたところ以外には応答しない。
スタブは呼び出しの情報を記録することもある。
例えば、Eメールゲートウェイスタブは「送られた」メッセージを記録するような場合だ。
単に「送られた」メールの数を記録する場合もあるだろう。

スタブによってデータベース接続やネットワークIOなどの要素をテストから分離することができる。
また時間のかかる処理をスタブで置き換えることによってテスト時間を短縮することにも使われる。


モックは、エクスペクテーションが事前にプログラムされたものである。
エクスペクテーションとは、受信する一連の呼び出しの仕様を表わしたものである。
期待されない呼び出しが行なわれた場合は例外をスローする。
また、テスト実行後の検証 (verification)で、期待された呼び出しがすべてきちんと行われたかどうかを確認する。

Railsで言うと、例えばコントローラのテストではモデルのモックを使ってコントローラがモデルを意図したとおりに使っているのかというところを検証する。
実際のモデルの代わりにモックを渡してコントローラがそれをどう使うかを見るわけだ。
モックは自分がどのように使われるべきかというエクスペクテーション(期待)を持ち、それと実際に自分が受けた扱いを比較して検証を行う。

モックによってモデルがなくてもインタフェースが決まっていればコントローラのテストを書いていけるし、逆にモデルの内部に直接手を突っ込むようなコードが書けないのでお互いの仕事が明確になるという効果もある。

これで理解が難しい場合はコードを書いてみるとわかると思う。コードの書き方については最後にまとめた参考サイトを参照。

モックとスタブの効能

モックとスタブを使う利点はいっしょに動作する個々のクラスやオブジェクトを(例えばコントローラとモデルおよびビュー)を完全に分離してテストできるという点だ。
それはお互いの役割をより明確にできて、よりシンプルかつ堅牢な設計にできると言うことでもある。

最初、モックとスタブを使い始めて既存のテストに適用しようとするとうまく組み込めなかった。
コントローラ内でモデルのモックを使おうとすると、エクスペクテーションが複雑になりすぎてどうにもうまくいかない。

これはモデルの中にもっと処理をまとめてインタフェースを単純化することで解決することができた。
結果、コントローラの中身がすっきりして見通しがよくなりメンテナンス性が上がったように思える。

今まではコントローラがモデルに細かくあれこれと口を出して動かしていたのが、今では一言かけるだけでモデルがテキパキと動くようになったみたいな。
「まかせれば人は楽しみ動き出す」ってやつだね。違うな。まあいいや。

とにかくモックやスタブによって自然と設計がよくなると思う。

モックとスタブの書き場所

サンプルコードは世にたくさんあるので特にここでは書かないがひとつだけ。
RSpecでモックとスタブを書き始めるときにちょっとだけ悩んだのが、モックとスタブのコードをどこに書くのか?というところ。
そこだけメモっておく。

これはテスト対象の処理の実行の前に書く。
すると処理の中でモックやスタブが使われるというスンポーだ。

そして以下の例ではindexアクションの処理の中で@item.some_methodが呼ばれていればモックのエクスペクテーションをパスする。

it "なにかのテストですよー" do
  # モック
  @item.should_receive(:some_method)

  # テスト対象の処理
  get :index

  # 普通のRSpecのエクスペクテーション
  @items.should be_true
end

参考サイト

参考サイトを見て実際手を動かすのが理解の早道という気がする。