0

問題

Relation を繰り返し処理し、各メンバーでメソッドを呼び出す関数があります。

def do_stuff
  count = 0
  foo.bars.active.each do |bar|
    bar.stuff
    count += 1
  end
  count
end

注:は、配列ではなく関係を返すactiveスコープです。bars

私のテストは次のようになりました:

describe :do_stuff do
  let(:foo) { FactoryGirl.create(:foo) }
  before    { foo.bars << FactoryGirl.create(:bar, :mock_stuff) }
  subject   { foo }
  it        { subject.do_stuff.should == 1 }
  it "does lots of stuff" do
    5.times { subject.bars << FactoryGirl.create(:bar, :mock_stuff) }
    subject.do_stuff.should == 6
  end
end

バーファクトリー

FactoryGirl.define do
  data { random_string }

  trait :mock_stuff do
    after_build { |bar| bar.stub(:stuff).and_return(true) }
  end
end

問題は、実際bar.stuffに呼び出されることを確認していないことです。これにリファクタリングしようとしたとき、私は自分自身を燃やしdo_stuffました:

def do_stuff
  foo.bars.active.count do |bar|
    bar.stuff
  end
end

countActiveRecord::Relation を呼び出してもブロックは実行されませんが、すべてのテストは引き続きパスします :(before仕様に次のようなブロックが必要です:

before do
  foo.bars.each do |bar|
    bar.should_receive(:stuff)
  end
end

問題は、bar上記で返されたインスタンスが、コードでインスタンス化されたインスタンスとは異なることです。

答え

私はついにそれを理解しました。以下は、配列またはリレーションを反復処理しているかどうかを心配する必要があり、心配しないときに失敗する仕様です。

describe :do_stuff do
  subject { FactoryGirl.create(:foo, :with_bar) }

  it "does stuff to bar" do
    Bar.any_instance.should_receive(:stuff)
    subject.do_stuff
  end
end

ここでの秘訣は、最初の例で行ったように、ブロック内で foo を定義できないことです。let

フーファクトリー:

FactoryGirl.define do
  data { random_string }

  trait :with_bar do
    after_build do |foo|
      foo.bars << FactoryGirl.create(:bar)
    end
  end
end

今、私が何か愚かなことをするfoo.bars.active.count do |bar|と、スペックが失敗し、コードが壊れていることがわかります。

4

1 に答える 1