Hatena::Groupcside

Cside::StudyMemo このページをアンテナに追加 RSSフィード

メインブログに書くまでもない自分用メモを垂れ流す。日々是勉強也。

カテゴリー

2012-09-17

[][]RSpecでMock/Stub

公式Doc: https://github.com/rspec/rspec-mocks/blob/master/README.md

そもそもMockとStubは何が違うか

自分はこういう理解でいる

Mockオブジェクトに対するメソッドの呼び出し方を検証する
Stubメソッドが正しい結果を返すかどうかを検証する。テスト範囲を限定するため、オブジェクトやインスタンスのメソッドの戻り値を固定する

以下の文章が理解の役に立った

相互作用中心のテスト*1とはテスト対象のシステムと外部のコンポーネントとの間で正しいやり取りがされるかのテスト、いわばプロトコルのテストです。外部のコンポーネントは Mock により置き換えられ、システムから正しい呼び出しがなされているかを監視します。

したがって、例えばWebアプリの Controller の単体テストにおいて相互作用中心のテストが正しく行われてパスしているならば、Model が正しく実装された時に Controller が正しく動作するということが、Model が実装されなくても保障されます。

一方状態中心のテスト*2とはテスト対象のシステムが正しい結果を返すかというテストです。したがって、最終的に返ってくる結果だけが重要なのですが、その過程において外部のシステムとの統合が面倒な時に Stub を利用してテストを簡単にします。なので、 Stub は信頼できる外部のコンポーネント(例えばDBとかLDAPとか)に対して適応するといいと思います。

ricollab Web Tech Blog » Blog Archive » Mock と Stub について

スタブは主に生成したりコントロールしたりするのに手間がかかるオブジェクトをもみ消す [stub out] のに使われる。典型的なのはデータベース接続だろう。

ttp://d.hatena.ne.jp/devbankh/201002

よく見るメソッド

名前 種類
should_receiveMock指定したメソッドが呼ばれないとテストが落ちる
with Mock指定した引数でメソッドが呼ばれないとテストが落ちる
and_return Stub指定したメソッドの結果を固定する
典型的な例

インスタンスbookのメソッドtitleの戻り値を "The RSpec Book" に固定する

book.stub(:title).and_return("The RSpec Book")

インスタンスvalidatorのメソッドvalidatorが02134という引数で呼ばれないとこける

validator = double("validator")
validator.should_receive(:validate).with("02134")

あと、下の例のようなのをよくみるけど、MockとStubをごっちゃにしてメソッドチェーンするのは、MockとStubの脳内スイッチ切り替えが追いつかなくて読むの苦労する。。。

Object.should_receive(:method).and_return(value)
ちょっと凝った使い方

メソッドが呼ばれた回数を検証する

double.should_receive(:msg).once
double.should_receive(:msg).twice
double.should_receive(:msg).exactly(n).times
double.should_receive(:msg).at_least(:once)
double.should_receive(:msg).at_least(:twice)
double.should_receive(:msg).at_least(n).times
double.should_receive(:msg).at_most(:once)
double.should_receive(:msg).at_most(:twice)
double.should_receive(:msg).at_most(n).times
double.should_receive(:msg).any_number_of_times

and_returnに複数の値を渡すと

こういうことができる

die.stub(:roll).and_return(1,2,3)
die.roll # => 1
die.roll # => 2
die.roll # => 3
die.roll # => 3
die.roll # => 3

ショートカット記法 double(), stub, mock()

以下の記述は、

book.stub(:title).and_return("The RSpec Book")

このように書くことが出来る。

book.stub(:title) { "The RSpec Book" }
book.stub(:title => "The RSpec Book")

book = double("book", :title => "The RSpec Book")
book =   stub("book", :title => "The RSpec Book")
book =   mock("book", :title => "The RSpec Book")

HTTP RequestのStub

これにはwebmockっていうライブラリがよく使われてる。

これはとはえさんの記事でも紹介されてた。

Perlと比較してみて

  • PerlではStubは広まってるけどMockをするモジュールってメジャーなのが無い気がする
    • Test::Mock::Guardでメソッドの呼び出し回数を参照できる、くらいかな

参考

  • ttp://d.hatena.ne.jp/takihiro/20081023/1224762895

*1:Mock

*2:Stub