RSpecのスタブとモック
まずはライブラリのクラスに対して使ってみましょう。
module Add def add_zero self.push 0 end end describe Array do before { @a = []; @a.stub!(:length).and_return(20) } #スタブはここで subject { @a.extend Add } its(:length) { should eq 20 } it 'calls #push when #add_zero is called' do subject.should_receive(:push).with(0).and_return([0]) #モックここ subject.add_zero end end
スタブについて
「スタブ(stub)」とはテストで他の実装に依存しないように使うの代用品で、たいていは一見完成しているように見えるものの中身は定数を返すだけものです。これをうまく使うと上位部品からでもテストしながら作り始めることができる素敵な子なのです。
RSpecでは、
オブジェクト.stub!(:メソッドの名前).and_return(返り値)
とすると、あるオブジェクトのメソッドがとりあえず返す値を設定することができます。ちなみに、すでにそのメソッドが完成していても容赦なく上書きするので、上の例のように空の配列なのにlengthが0ではなく20を返すようにすることもできます*1。
モックについて
これはメソッドがちゃんと期待したとおりに呼ばれているかどうか確かめるための仕組みです。
今回は自身に0を突っ込むAdd#add_zeroなる必要性はあまりないメソッドが、pushをちゃんと呼び出しているかどうかを確かめています。
オブジェクト.should_receive(:メソッドの名前).with(引数).and_return(返り値)
どうでもいいけどreceiveとrecieveよく間違えるのなんとかしたい
その結果どうなるかというと、
モックとスタブを使う利点はいっしょに動作する個々のクラスやオブジェクトを(例えばコントローラとモデルおよびビュー)を完全に分離してテストできるという点だ。
それはお互いの役割をより明確にできて、よりシンプルかつ堅牢な設計にできると言うことでもある。(中略)
とにかくモックやスタブによって自然と設計がよくなると思う。
最後大事。
*1:上のテストがちゃんとグリーンになることは確認済み