RSpecにおけるコンテキストをまたぐ共通部分

先日書いた SeleniumRC spec の中で使ってたテクニックが最近、会社で流行ってる。

2007-12-04追記: このテクニックはRSpec 0.8以前のために開発しました。RSpec 1.0以降ではshared behaviourを使いましょう。ただ、RSpecをいじくる技法の基礎として参考にはなるかもしれません。

コンテキストにおける共通の初期化処理は勿論、setupやcontext_setupに書けばいいんだけど、問題は複数のコンテキストにまたがる共通の初期化処理。あるいは、modelのspecでfixtureを設定したり、controllerのspecにおいてコントローラー名を指定したり。

これらって、いちいち書くのがなんかDRYじゃない気がする。特に、1つのmodelに対するspecがcontextから構成されるとき(諸橋さん方式。contextという言葉の意味合いから言えば、無理に1つのコンテキストにするよりこの方が自然なはず)、でもfixtureの読み込みは毎回同じだったり。コントローラー指定はよく書き忘れるけど、書き忘れるとよく分からないエラーが出るし。

で、こうするわけだ。model Hogeに対するspecであるとすれば、そのspecファイルの頭でこんなメソッドを定義する。

def hoge_context(*args, &block)
  context(*args) do
    fixtures :hoge, :huga, :hugu

    context_setup do
       # なんか共通の初期化
    end

    instance_eval(&block) 
  end
end

で、以降はcontextの代わりにhoge_contextを使用する。DRYで安全。お手軽簡単。