Reputation: 17599
So based on my understanding, I beleive when you do
Resque.inline = Rails.env.test?
Your resque tasks will run synchronously. I am writing a test on resque task that gets enqueue during an after_commit
callback.
after_commit :enqueue_several_jobs
#class PingsEvent < ActiveRecord::Base
...
def enqueue_several_jobs
Resque.enqueue(PingFacebook, self.id)
Resque.enqueue(PingTwitter, self.id)
Resque.enqueue(PingPinterest, self.id)
end
In the .perform
methd of my Resque task class, I am doing a Rails.logger.info
and in my test, I am doing something like
..
Rails.logger.should_receive(:info).with("PingFacebook sent with id #{dummy_event.id}")
PingsEvent.create(params)
And I have the same test for PingTwitter
and PingPinterest
.
I am getting failure on the 2nd and third expectation because it seems like the tests actually finish before all the resque jobs get run. Only the first test actually passes. RSpec then throws a MockExpectationError
telling me that Rails.logger
did not receive .info
for the other two tests. Anyone has had experience with this before?
Someone mentioned that should_receive
acts like a mock
and that I should do .exactly(n).times
instead. Sorry for not making this clear earlier, but I have my expectations in different it
blocks and I don't think a should_receive
in one it
block will mock it for the next it
block? Let me know if i'm wrong about this.
Upvotes: 2
Views: 1093
Reputation: 1546
Using should_receive
behaves like a mock. Having multiple expectations on the same object with different arguments won't work. If you change the expectation to Rails.logger.should_receive(:info).exactly(3).times
your spec will probably past.
All that said, you may want to assert something more pertinent than what is being logged for these specs, and then you could have multiple targeted expectations.
The Rails.logger
does not get torn down between specs, so it doesn't matter if the expectations are in different examples. Spitting out the logger's object id for two separate examples illustrates this:
it 'does not tear down rails logger' do
puts Rails.logger.object_id # 70362221063740
end
it 'really does not' do
puts Rails.logger.object_id # 70362221063740
end
Upvotes: 1
Reputation: 47568
class A
def bar(arg)
end
def foo
bar("baz")
bar("quux")
end
end
describe "A" do
let(:a) { A.new }
it "Example 1" do
a.should_receive(:bar).with("baz")
a.foo # fails 'undefined method bar'
end
it "Example 2" do
a.should_receive(:bar).with("quux")
a.foo # fails 'received :bar with unexpected arguments
end
it "Example 3" do
a.should_receive(:bar).with("baz")
a.should_receive(:bar).with("quux")
a.foo # passes
end
it "Example 4" do
a.should_receive(:bar).with(any_args()).once
a.should_receive(:bar).with("quux")
a.foo # passes
end
end
Like a stub, a message expectation replaces the implementation of the method. After the expectation is fulfilled, the object will not respond to the method call again -- this results in 'undefined method' (as in Example 1).
Example 2 shows what happens when the expectation fails because the argument is incorrect.
Example 3 shows how to stub multiple invocations of the same method -- stub out each call with the correct arguments in the order they are received.
Example 4 shows that you can reduce this coupling somewhat with the any_args()
helper.
Upvotes: 2