オブジェクトが他のオブジェクトと相互作用するにあたり、そのオブジェクトの機能の全体が必要になることは少ない。むしろ、オブジェクトの提供する特定のRoleのみが見えるべきである。そのRoleを提供することのみを契約すべきである。
MVCアーキテクチャではControllerはModelに対してオブザーバとして振る舞うし、Viewに対しては何らかのメッセージソースとして振る舞う。MVC風webフレームワークではControllerはViewに対して、表示すべきデータを供給する役割だし、一方でHTTPリクエストの消費者として振る舞う。
さて、ある種の静的型付け言語ではこのRoleをinterfaceという言語要素で表すことができる。そして、契約違反はコンパイルエラーとして検出することが可能だ。その言語の上のフレームワークが、適切にinterfaceで契約を結んでいるかは別として。
これをRubyにおいてどう実現しようか。RSpecで慎重に記述することで勿論実現はできる。しかし、各コンポーネントのspecが整合性を保ち提供された契約のみに依存し提供すべき契約を果たしていることを「慎重に」記述しなければならない時点で敗北である。
依存性を断ち切るためにスタブを使う。だが、スタブを用いることで相手方のコンポーネントが契約を果たしてくれているかどうか検証不能になる。だから、提供すべき契約内容を1個のspec(Example Group)として記述しよう。そして、そのspecからスタブを生成しよう。
describe HogeModel do it "have a name" do HogeModel.new.should respond_to(:name) end end describe HogeController, "ほげほげした場合の、hoge.html.erbに対して" do it "provdes @hoge" do post :hoge assigns[:hoge].should behave_like(HogeModel) end end describe "hoge.html.erb" do before do stub_assigns_like(HogeController, "ほげほげした場合の、hoge.html.erbに対して") end it "...." end
こんなスタブライブラリはあるかな? 無けりゃ書こう。