Reputation: 14029
I was wondering how to test a find_each call in rspec. I'm used to simply stubbing what I want my models to return so I don't rely on test data in the db like this:
MyClass.stub(:find).and_return(my_mock)
However, in another class I'm doing this:
MyClass.find_each do |instance_of_my_class|
do_stuff_here_on(instance_of_my_class)
end
I find that if I do this:
MyClass.stub(:find_each).and_return([one_mock, two_mock])
in the spec test, the "do stuff here" part is not being executed. Does anyone know how to stub a find_each for rspec testing?
Upvotes: 39
Views: 11391
Reputation: 99
If you need to stub find_each
on a verified double and have it loop through a specific array of values, you can do this:
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
Upvotes: 4
Reputation: 4203
You can use and_yield to make rspec call the block passed to the mock:
MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
Upvotes: 53
Reputation: 875
This should do it:
MyClass.stub(:find_each) {|block|
block.call
[one_mock, two_mock]
}
If do_stuff_here_on isn't globally reachable, e.g. an instance method on some_object, you'll need some instance_eval to get the right scope for the block:
MyClass.stub(:find_each) {|block|
some_object.instance_eval(&block)
[one_mock, two_mock]
}
Upvotes: 1
Reputation: 51697
The whole point of stubbing a method is so that the method returns an expected value and not execute its contents. If you have a bunch of logic within the find_each method, I would recommend moving it to a separate method and testing that logic separately. You can then test that your method is called during execution.
Here's a pretty high level example:
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
Upvotes: 2