RSpec 2.4/2.6でヘルパーのテストをしていてはまった話

rails new hello worldとしてRSpecの設定をしただけの状態で以下を作成する。まずテストのコード:

describe HelloHelper do
  describe '#each_productは' do
    it '@productに値を設定してyieldすること' do
      assign(:products, [
        mock_model('Product', :price => 100),
      ])

      output = helper.each_product do
        helper.product_price
      end

      output.should == '100'
    end
  end
end
次にヘルパーのコード:
module HelloHelper
  def each_product(&block)
    buf = ''
    @products.each do |product|
      @product = product
      buf << capture(&block)
    end
    buf
  end

  def product_price
    @product.price.to_s
  end
end
これは通る。 この状態からしばらくして他のテストを書いていくうちに、こんなのを加えたとする。
describe HelloHelper do
  before do
    assign(:product,
           mock_model('Product', :price => 1))
  end
  ...

ありがちな書き方だと思うのだけど、どうだろう。そしてこれの変化によりテストを走らせると結果がこのようになる。

F

Failures:

  1) HelloHelper#each_productは @productに値を設定してyieldすること
     Failure/Error: output.should == '100'
       expected: "100"
            got: "1" (using ==)
     # ./spec/helpers/hello_helper_spec.rb:28

Finished in 0.02024 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/helpers/hello_helper_spec.rb:20 # HelloHelper#each_productは @productに値を設定してyieldすること

先の追加のコードが、こういうものだったら影響はない:

  before do
    assign(:_product,
           mock_model('Product', :price => 1))
  end

だが、よりやっかいなことに、こういうコードだと影響を受ける:

  before do
    @product =
      assign(:foo,
             mock_model('Product', :price => 1))
  end

テストの結果はやはりこう:

F

Failures:

  1) HelloHelper#each_productは @productに値を設定してyieldすること
     Failure/Error: output.should == '100'
       expected: "100"
            got: "1" (using ==)
     # ./spec/helpers/hello_helper_spec.rb:29

Finished in 0.02026 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/helpers/hello_helper_spec.rb:21 # HelloHelper#each_productは @productに値を設定してyieldすること