mazinlabsのブログ

RubyとかCloudとかその辺の記事を書いたり書かなかったり

shared_examples_forが便利

RSpecのテストをグルーピングして実行できる#shared_examples_forが便利。

Shared example group - Example groups - RSpec Core - RSpec - Relish

これを使えばテストコードが簡潔になるのでテストコードの量を減らすことができる。

require "set"

shared_examples_for "a collection" do
  let(:collection) { described_class.new([7, 2, 4]) }

  context "initialized with 3 items" do
    it "says it has three items" do
      collection.size.should eq(3)
    end
  end

  describe "#include?" do
    context "with an an item that is in the collection" do
      it "returns true" do
        collection.include?(7).should be_true
      end
    end

    context "with an an item that is not in the collection" do
      it "returns false" do
        collection.include?(9).should be_false
      end
    end
  end
end

describe Array do
  it_behaves_like "a collection"
end

describe Set do
  it_behaves_like "a collection"
end

ブロックを渡してやることもできるしパラメータを渡してやることもできる。

require "set"

shared_examples_for "a collection" do
  let(:collection) { described_class.new([7, 2, 4]) }

  context "initialized with 3 items" do
    it "says it has three items" do
      collection.size.should eq(3)
    end
  end

  describe "#include?" do
    context "with an an item that is in the collection" do
      it "returns true" do
        collection.include?(7).should be_true
      end
    end

    context "with an an item that is not in the collection" do
      it "returns false" do
        collection.include?(9).should be_false
      end
    end
  end
end

describe Array do
  it_behaves_like "a collection"
end

describe Set do
  it_behaves_like "a collection"
end
require "set"

shared_examples_for "a collection object" do
  describe "<<" do
    it "adds objects to the end of the collection" do
      collection << 1
      collection << 2
      collection.to_a.should eq([1,2])
    end
  end
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を書きなおしてみたら動かなかった。
ちなみにこんな感じのコードを実行すると以下のようにundefined methodって言われる。

require "set"

shared_examples_for "a collection object" do
  describe "<<" do
    it "adds objects to the end of the collection" do
      collection << 1
      collection << 2
      collection.to_a.should eq([1,2])
    end
  end
end

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

describe Set do
  it_should_behave_like "a collection object" do
    let(:collection) { Set.new }
  end
end
Failures:

  1) Array sample_examples_for_test
     Failure/Error: it_should_behave_like "a collection object" do
     NoMethodError:
       undefined method `it_should_behave_like' for #
     # ./sample_spec.rb:15:in `block (2 levels) in '

色々考えて試行錯誤を重ねた結果ようやく自分のミスに気づく。
it句の中にit_should_behave_likeって書いても動かないらしい。


といわけで、RSpecを書いてる中で上記のようにundefined methodって言われたら書く場所が違うことを疑ってみましょう!


それはともかくshared_examples_for便利!