39

rspecでfind_each呼び出しをテストする方法を考えていました。私はモデルに返してほしいものを単純にスタブすることに慣れているので、次のようにデータベース内のテストデータに依存しません。

MyClass.stub(:find).and_return(my_mock)

ただし、別のクラスでは、これを行っています。

MyClass.find_each do |instance_of_my_class|
  do_stuff_here_on(instance_of_my_class)
end

私がこれを行うと、私はそれを見つけます:

MyClass.stub(:find_each).and_return([one_mock, two_mock])

スペックテストでは、「ここで何かをする」部分は実行されていません。rspecテストのためにfind_eachをスタブ化する方法を知っている人はいますか?

4

4 に答える 4

53

and_yieldを使用して、rspecにモックに渡されたブロックを呼び出させることができます。

MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
于 2010-12-08T07:15:11.190 に答える
2

メソッドをスタブ化することの全体的なポイントは、メソッドが期待値を返し、その内容を実行しないようにすることです。find_eachメソッド内に多数のロジックがある場合は、それを別のメソッドに移動して、そのロジックを個別にテストすることをお勧めします。次に、実行中にメソッドが呼び出されることをテストできます。

これはかなり高レベルの例です:

class Example1
  def my_method
    # some logic
  end
end

class Example2
  def my_other_method
    Example1.find_each(&:my_method)
  end
end

Rspec:

describe Example1 do
  it "should return something" do
    example = Example1.new
    example.my_method.should == something
  end
end

describe Example2 do
  it "should call my_method on Example1" do
    example1 = mock(:example1, :my_method => true)
    example2 = Example2.new

    example1.should_receive(:my_method)
    example2.my_other_method
  end
end
于 2010-12-08T02:15:39.243 に答える
2

検証済みのdoubleをスタブfind_eachし、特定の値の配列をループさせる必要がある場合は、次のように実行できます。

let(:my_relation_with_mocked_find_each) do
  relation = instance_double('YourModel::ActiveRecord_Relation')

  receive_yield = receive(:find_each)

  fake_objs.each do |obj|
    receive_yield = receive_yield.and_yield(obj)
  end

  allow(relation).to receive_yield
  relation
end
于 2018-10-01T13:30:58.643 に答える
1

これはそれを行う必要があります:

MyClass.stub(:find_each) {|block|
  block.call
  [one_mock, two_mock]
}

do_stuff_here_onがグローバルに到達できない場合、たとえばsome_objectのインスタンスメソッドの場合、ブロックの適切なスコープを取得するには、instance_evalが必要です。

MyClass.stub(:find_each) {|block|
  some_object.instance_eval(&block)
  [one_mock, two_mock]
}
于 2011-11-21T08:47:29.243 に答える