Search code examples
ruby-on-railsruby-on-rails-3rspecrspec2resque

How do you separate test queues and real queues when testing Resque (with rspec and rails?)


I would like to test some resque workers, and the actions that enqueue jobs with these workers. I am using rspec and rails.

Currently I have a model, let's call it Article.rb, that has a before_save method called updates_related_categories that checks if a job with CategoriesSorter needs to be enqueued. If so, it enqueues a job with that worker, with the argument of the category id that the article is related to.

In test, however, these jobs are sent to the same queue as the development server sends jobs to. (i check using the resque server that you can tie into your server at root/redis/overview)

I want to know:

1) How can I send test jobs to a different queue than the development jobs?

If this is possible, any other advice on testing resque is also welcome.

I have seen some related questions that suggest resque-unit and resque-spec but these are pretty undeveloped, and I couldn't get them to a useful working state. Also, I have heard of using Resque.inline but I don't know if that is relevant in this case, as resque isn't called in test specs, it's called from the article model on save of objects created in test.

Sample Code:

Article.rb:

 before_save :update_related_categories
 def update_related_categories
     #some if statements/checks to see if a related category needs updating
         Resque.enqueue(CategoriesWorker, [category_id])
     end
 end

CategoriesSorter:

 class CategoriesSorter
     @queue=:sorting_queue
     def self.perform(ids)
        ids.each do |id|
           #some code
        end
      end
 end

Specs:

 it "should do something" do
     @article = #set something to enqueue a job
     @article.save
     #can i check if a job is enqueued? can i send this job NOT to the development queue but a different one?
 end

Solution

  • As I see it, you don't want to test whether enqueueing the job results in perform being called - we trust Resque does what it should. However, you can test that 1. calling update_related_categories enqueues the job. Then you can test, separately, whether 2. a worker calling perform results in the desired behavior.

    For testing Resque in general, a combination of resque-spec and simulating a worker can accomplish the above two goals.

    For 1, with resque-spec, you can simulate a worker calling the perform method on your class, and then check that it has been enqueued correctly:

    describe "Calling update_related_categories " do
      before(:each) do
        ResqueSpec.reset!
      end
    
      it "should enqueue the job" do
        Article.update_related_categories
        CategoriesSorter.should have_queue_size_of(1)
      end
    end
    

    For 2, you can create a Job (and specify a separate queue name than your development queue), a Resque::Worker and then assign the Worker to the Job:

    def run_worker_simulation
      # see Resque::Job api for setting the args you want
      Resque::Job.create('test_queue_name', 'class_name', 'type', 'id')
    
      worker = Resque::Worker.new('test_queue_name')
      worker.very_verbose = true
    
      job = worker.reserve
      worker.perform(job)
    end
    

    Hope that gives you some ideas.