Search code examples
ruby-on-railsrspecresqueresque-retry

Setting expectation on resque .perform method. Task is enqueued in a Callback


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?

EDIT

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.


Solution

  • 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.