Ruby
RSpec

shared contextにタグをつけて自動的にincludeする

More than 1 year has passed since last update.

RSpecのshared contextはもちろんご存知ですよね。

参考: shared_context - 改めて学ぶ RSpec

うまく使ってあげることができたならDRYで可読性の高いコードになるのですが、いちいち context の名前を打たないといけないのがだるい!
切られた context は文章の形をとっていることが多いので多くのエディタの補完機能でも打鍵数が多くなってしまいます (単語ベースの補完がほとんどのため)。

我々はこのまま「要素がふたつpushされている」なんて文章をずっと書かねばならないのでしょうか?
やはりプログラムのコード、人間が楽をしようだなんて所詮は夢のような話だったのでしょうか。
いいえ、そんなことはありません。人間はテストコードともっと仲良くなれる、そうRSpecならね。

タグを使います。

タグは example groups などを切るメソッド (it, specify, describe, context) のオプション引数として渡すことができます。
Capybaraを使って request specs を記述するときに describe "the signup", type: :request do と書きますが、最後に渡しているハッシュがそれです。

既に使っている方も少なくないかもしれません。

るびまのコード例を引用します。

shared_context '要素がふたつpushされている' do
  let(:latest_value) { 'value2' }
  before do
    @stack = Stack.new
    @stack.push 'value1'
    @stack.push latest_value
  end
end

describe Stack do
  describe '#size' do
    include_context '要素がふたつpushされている'
    subject { @stack.size }
    it { should eq 2 }
  end

  describe '#pop' do
    include_context '要素がふたつpushされている'
    subject { @stack.pop }
    it { should eq latest_value }
  end
end

include_context '要素がふたつpushされている' をもう二度と書きたくないですね。

こうします:

shared_context '要素がふたつpushされている', items: 2 do
  let(:latest_value) { 'value2' }
  before do
    @stack = Stack.new
    @stack.push 'value1'
    @stack.push latest_value
  end
end

describe Stack do
  describe '#size', items: 2 do
    subject { @stack.size }
    it { should eq 2 }
  end

  describe '#pop', items: 2 do
    subject { @stack.pop }
    it { should eq latest_value }
  end
end

これでOKです。便利。

注意したいのは shared context は明示的にせよ暗黙的にせよ、include する前に定義されていなければならないということです。
shared context は別のファイルに括り出して複数の *_spec.rb から呼び出して使うこともできますから、規模が大きくなってきたら利用するのも手かもしれません。