-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Testing
Sidekiq provides a few options for testing your workers.
Sidekiq provides the following three testing modes:
- A test fake that pushes all jobs into a
jobsarray - An inline mode that runs the job immediately instead of enqueuing it
- The test harness can be disabled. Jobs are pushed to redis.
Sidekiq allows you to dynamically configure the testing harness with the following methods:
require 'sidekiq/testing'
Sidekiq::Testing.fake! # fake is the default mode
Sidekiq::Testing.inline!
Sidekiq::Testing.disable!Each of the above methods also accepts a block. An example:
require 'sidekiq/testing'
Sidekiq::Testing.fake!
# Some tests
Sidekiq::Testing.inline! do
# Some other tests
end
# Here we're back to fake testing again.To query the current state, use the following methods:
Sidekiq::Testing.enabled?
Sidekiq::Testing.disabled?
Sidekiq::Testing.fake?
Sidekiq::Testing.inline?Similar to the ActionMailer testing API, instead of pushing jobs to Redis, Sidekiq pushes them into a jobs array which you can access. Require the sidekiq/testing file in your {test,spec}_helper.rb and set the mode:
require 'sidekiq/testing'
Sidekiq::Testing.fake!Then assert that jobs were pushed on to the queue:
expect {
HardWorker.perform_async(1, 2)
}.to change(HardWorker.jobs, :size).by(1)assert_equal 0, HardWorker.jobs.size
HardWorker.perform_async(1, 2)
assert_equal 1, HardWorker.jobs.sizeYou can execute all queued jobs by draining the queue:
HardWorker.perform_async(1, 2)
HardWorker.perform_async(2, 3)
assert_equal 2, HardWorker.jobs.size
HardWorker.drain
assert_equal 0, HardWorker.jobs.sizeTo execute all workers' queued jobs:
Sidekiq::Worker.drain_allIf you would like to remove jobs from the queue without actually performing them:
HardWorker.perform_async(1, 2)
HardWorker.clear
assert_equal 0, HardWorker.jobs.sizeTo clear all workers' jobs:
Sidekiq::Worker.clear_allThis can be useful to make sure jobs don't linger between tests:
RSpec.configure do |config|
config.before(:each) do
Sidekiq::Worker.clear_all
end
endmodule SidekiqMinitestSupport
def after_teardown
Sidekiq::Worker.clear_all
super
end
end
class MiniTest::Spec
include SidekiqMinitestSupport
end
class MiniTest::Unit::TestCase
include SidekiqMinitestSupport
endA testing API for queues is available in 4.0+. This is helpful when the Worker class does not exist in the application being tested. One might enqueue a job using Sidekiq::Client:
Sidekiq::Client.push(
'class' => 'NonExistentWorker',
'queue' => 'other',
'args' => [1]
)Since the NonExistentWorker doesn't exist in the application, we can assert the job made it to the queue:
assert_equal 0, Sidekiq::Queues["other"].size
Sidekiq::Client.push(
'class' => 'NonExistentWorker',
'queue' => 'other',
'args' => [1]
)
assert_equal 1, Sidekiq::Queues["other"].size
assert_equal "NonExistentWorker", Sidekiq::Queues["other"].first["class"]
# Clear an individual queue
Sidekiq::Queues["other"].clear
# Clear all queues (equivalent to Sidekiq::Worker.clear_all)
Sidekiq::Queues.clear_allTo test your worker directly, just treat it like a ruby object. Easy!
work = HardWorker.new
work.perform(1, 2)You can run Sidekiq workers inline in your tests by requiring the sidekiq/testingfile in your {test,spec}_helper.rb and setting the mode:
require 'sidekiq/testing'
Sidekiq::Testing.inline!
# or use block mode to avoid leaking the setting into other tests
Sidekiq::Testing.inline! do
HardWorker.perform_async
assert_worked_hard
endJobs will then be executed immediately when they are placed on the queue.
You can access the jobs queue from Sidekiq::Extensions::DelayedMailer (ActionMailer), Sidekiq::Extensions::DelayedModel (ActiveRecord), or Sidekiq::Extensions::DelayedClass (everything else) similarly.
assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
MyMailer.delay.send_welcome_email('foo@example.com')
assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.sizeBy default, the test harness (in either mode) does not run any server side middleware. You can add middleware to the harness with the following:
Sidekiq::Testing.server_middleware do |chain|
chain.add AwesomeMiddleware
endMiddleware in the Sidekiq::Testing.server_middleware stack will be run in inline mode whenever jobs are run and in fake mode whenever .drain or .perform_one are called.
Sidekiq's API does not have a testing mode, e.g. something like Sidekiq::ScheduledSet.new.each(...) will always hit Redis. You can use Sidekiq::Testing.disable! to set up jobs in order to use the API in your tests against a real Redis instance.
Batches are a high-level integration between many jobs. It's difficult to actually run the full batch implementation when testing: I suggest firing callbacks manually rather than trying to set up the batch middleware.
Sidekiq::Testing.inline! do
b = Sidekiq::Batch.new
b.on(:success, SomeCallback)
b.jobs do
# inline will perform jobs immediately
5.times { HardWorker.perform_async }
end
# fire callback manually
SomeCallback.new.on_success(nil, nil)
endSee the rspec-sidekiq gem.