前書きの部分でShouldaというライブラリーが紹介されているが、今であればshoulda_matchersを使うのが良さそう。
ちなみにrailsのテスト手法については現在でも意見が割れている話なので、あくまで参考程度にお読みください。
アンチパターン: fixures
一応話しておくと、fixturesというのはRailsのデフォルトで付いているテストデータ生成用の機能で、適切な場所に置かれた .ymlファイルからレコード、オブジェクトを生成する技術。(簡単な解説エントリ)
この本ではfixtruesの以下の点を主な欠点として揚げている
- 適切なfixtureを用意するコストが高い
- オブジェクトの関連を表現する手段に乏しい
- DBのバリデーションを通らない
ソリューション:Factory(Girl)を使おう
一連の関連するオブジェクトを生成するにはFactoryパターンというパターンが適している。Factoryクラスは他のクラスのインスタンスを生成する責任を持つ。クラスの実装が変わってもFactoryを変えればよい。
RailsにはFactoryパターンを利用してテストデータを作成してくれるFactoryGirlというgemがあるので使おう。
また、contextという単位でてテストケースを分割することも勧めている。比較例としてあげられているのはassertion用のtest_caseメソッドをひたすら書く、というものでさすがにこんなことしてる人はいない、と思ったけど。
rspecを使っていればそのまま解決できる。
アンチパターン:テスト同士が独立していない
mock,stubという技術がある。テストしたい部分に関連する部分だけの振る舞いを指定する技術で、例えば外部APIに依存する操作をするコードをテストするときや、メソッドの出力をとりあえず指定する、みたいなことをする。(MatinFawler先生の解説)
スタブは主に生成したりコントロールしたりするのに手間がかかるオブジェクトをもみ消す [stub out] のに使われる。(中略)
スタブは、実際のオブジェクトと代替できるようインターフェースの実装をし、実際のメソッドをシンプルな [テスト用に] 準備されたデータを使うメソッドで置き換えることで作られる。
モック
「オブジェクトのメソッドがどう呼ばれて何を返すか」というインタフェースも含めたテストのために使う
スタブ
テストをスムーズに行うために「あるオブジェクトのメソッドが呼ばれたら、ある戻り値を返す」ために使う
とのこと。
簡単に言えば、stubingとはユニットテストに対する統合テストまでのバッファである。結合部分をごまかしているので、この部分をテストしていないと結合動作だけは保証されなくて、本番で落ちる、みたいなことになる。
ただ、TDDのいいところはテストを書いてる間にそのクラスのインターフェースについて考えれるようになること。stubingしにくいということはクラス同士が密結合である可能性が高い。stubingを多用することが必ずしも良しというわけではないがstubingしやすいコードはいいコードということができるだろう。
しかしオブジェクトに「尋ねる」コードを書いていると、細かいメソッドチェーンをstubしていくコードで溢れてくる。これは良くない傾向だ。
相互作用するオブジェクトに対して、値を「尋ね」、その値を操作する、というコードは良いコードではない。
ロジックは値を持つ側のオブジェクトに実装し、利用する側はただ「命じる」ようにすべきだ。これがオブジェクト指向の"Don't ask, tell"にあたる。こうすればそのメソッドをstubingするだけでテストが書けるようになる。
結論:FactoryGirl-RSpecを使おう(ただしこれに関しては賛否両論)。結合テスト無しにstubばかりを増やすのは危険だが、stubしやすいコードを心がけよう。"Don't ask, Tell"の法則が参考になる。
ちなみに
http://nilp.hatenablog.com/entry/2014/06/01/165448 (railsコントリビュターのrspec-factroyGirlあんまり好きじゃないポエム)
http://blog.steveklabnik.com/posts/2012-07-14-why-i-don-t-like-factory_girl (urlの通り)