すごいぞRSpec(shared example group編)

ちょっと前に話題になったRSpecのスライドがステキだったよね。でもRSpecはまだまだ底知れない気がするので自分でもいろいろと調べてみようと思った次第。

まずはrspec-core(2.5.1)/features/example_groups/shared_example_group.featureを参考にshared example groupについて調べてみたよ。

例1:テストを共有できる

require "set"

shared_examples_for 'a collection' do
  subject { described_class.new [7, 2, 4] }
  its(:size) { should eq 3 }
  it { should include 7 }
  it { should_not include 9 }
end

describe Array do
  it_behaves_like 'a collection'
end

describe Set do
  it_behaves_like 'a collection'
end
% rspec -cfs shared_example_group_1.rb

Array
  behaves like a collection
    should include 7
    should not include 9
    size
      should == 3

Set
  behaves like a collection
    should include 7
    should not include 9
    size
      should == 3

まぁ単純に使うとこうなる。同じテストをあちこちに書いてたらDRYに反するのでまとめれると嬉しいよね。ここまでは知ってた。described_classも何かと使えそうな気がする。

例2:ブロックを渡せる

require "set"

shared_examples_for 'a collection object' do
  subject { collection << 1 << 2 }
  its(:to_a) { should eq [1,2] }
end

describe Array do
  it_should_behave_like 'a collection object' do
    let(:collection) { Array.new }
  end
end

describe Set do
  it_should_behave_like 'a collection object' do
    let(:collection) { Set.new }
  end
end
% rspec -cfs shared_example_group_2.rb

Array
  it should behave like a collection object
    to_a
      should == [1, 2]

Set
  it should behave like a collection object
    to_a
      should == [1, 2]

Finished in 0.00189 seconds
2 examples, 0 failures

ブロックを渡すとそれぞれのサンプルでいい按配で使ってくれるみたいなのでこれは便利そう。

例3:引数を渡せる

shared_examples_for 'a measurable object' do |measurement, measurement_methods|
  measurement_methods.each do |measurement_method|
    its(measurement_method) { should == measurement }
  end
end

describe Array, 'with 3 items' do
  subject { [1, 2, 3] }
  it_should_behave_like 'a measurable object', 3, [:size, :length]
end

describe String, 'of 6 characters' do
  subject { 'FooBar' }
  it_should_behave_like 'a measurable object', 6, [:size, :length]
end
% rspec -cfs shared_example_group_3.rb

Array with 3 items
  it should behave like a measurable object
    size
      should == 3
    length
      should == 3

String of 6 characters
  it should behave like a measurable object
    size
      should == 6
    length
      should == 6

Finished in 0.00215 seconds
4 examples, 0 failures

若干ややこしいし、使いどころが難しいような気がするが、上手く使えればシンプルにまとめられる場面はあるように思う。

例4:it_should_behave_likeじゃなくできる

RSpec.configure do |c|
  c.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
end

shared_examples_for 'sortability' do
  it { should respond_to :<=> }
end

describe String do
  it_has_behavior 'sortability' do
    subject { 'sample string' }
  end
end
% rspec -cfs shared_example_group_4.rb

String
  has behavior: sortability
    should respond to #<=>

Finished in 0.00275 seconds
1 example, 0 failures

it_should_behave_likeって長すぎるしイマイチよくわからないよね。ってときはなんとエイリアスできるようだ。出力メッセージも変えれる。


といったところでやっぱりRSpecはまだまだ掘れそうな雰囲気です。いきなりletとかitsとかimplicit subjectとか使いまくってるんで、最初にshared example groupもってきたのは失敗な気がするけどまぁいいか。その辺についてはあとで書く。


続く。