Reputation: 8941
I have a class method that just iterates through some records and performance an instance method on each record. I am trying to write a simple test for the class method just to make sure that it's sending the instance method to each record.
it "fires any pending alarms" do
pending = create :alarm, :pending
other_pending = create :alarm, :pending
# sanity check
Alarm.pending.sort.should eq [pending, other_pending].sort
pending.should_receive(:fire)
other_pending.should_receive(:fire)
Alarm.fire_pending
end
alarm.rb
class Alarm < ActiveRecord::Base
scope :pending, where(pending: true)
def self.fire_pending
self.pending.each do |alarm|
alarm.fire
end
end
end
But I am receiving an error on both should_receive
expectations:
Failure/Error: pending.should_receive(:fire)
(#<Alarm:0x007fcc96334310>).fire(any args)
expected: 1 time
received: 0 times
I have used this expectation before successfully. I'm afraid that I'm missing something obvious.
edit
I've worked around it for now with this:
it "fires any pending alarms" do
pending = create :alarm, :pending
other_pending = create :alarm, :pending
pending_alarms = Alarm.pending
pending_alarms.sort.should eq [pending, other_pending].sort
Alarm.stub(:pending) { pending_alarms }
pending_alarms.first.should_receive(:fire)
pending_alarms.last.should_receive(:fire)
Alarm.fire_pending
end
But I don't really like that and would like to know why my first try doesn't work.
Upvotes: 1
Views: 1770
Reputation: 9000
The objects returned by Alarm.pending
are not the same instances created in the example. You can see this by changing:
pending_alarms.sort.should eq [pending, other_pending].sort
to:
# the eq matcher uses == (object equivalence)
# the equal matcher uses equals? (object identity)
pending_alarms.sort.tap do |sorted|
sorted[0].should eq pending # passes
sorted[1].should eq other_pending # passes
sorted[0].should equal pending # fails
sorted[1].should equal other_pending # fails
end
This is a good case for using (the evil) any_instance
:
it "fires any pending alarms" do
pending = create :alarm, :pending
Pending.any_instance.should_receive(:fire)
Alarm.fire_pending
end
Upvotes: 6