This post was originally posted on Max's blog, Maxgrok.
Introduction
Sidekiq runs background jobs for Rails apps. Officially, Sidekiq is "simple, efficient background processing for Ruby."
In a Rails app, I was working on I was tasked with building a Sidekiq worker that sent an in-app notification and an email in the future to users for a To Do list.
After spending some time Googling, I've decided to help others who may Google for how to test a Sidekiq worker, especially at testing a worker at a specific time, by writing about how to do it, in one blog post.
We are going to use Sidekiq and also rspec-sidekiq to do testing. I will go over configuration for rspec-sidekiq
, but not Sidekiq (as this is well documented).
Configure Your Rails App for 'rspec-sidekiq'
Run gem install rspec-sidekiq
within your project root directory.
Then, in rails_helper.rb
, include the following:
require 'sidekiq/testing/inline'
require 'sidekiq-status/testing/inline'
RSpec::Sidekiq.configure do |config|
# Clears all job queues before each example
config.clear_all_enqueued_jobs = true # default => true
# Whether to use terminal colours when outputting messages
config.enable_terminal_colours = true # default => true
# Warn when jobs are not enqueued to Redis but to a job array
config.warn_when_jobs_not_processed_by_sidekiq = true # default => true
end
Writing Your Tests
Name your RSpec file in spec/workers/worker_name_here_spec.rb
by convention, then add the following at the top of your RSpec file:
require 'rails_helper'
require 'sidekiq/testing'
Sidekiq::Testing.fake!
Now, let's see some examples of tests you might like to run on your Sidekiq worker.
For testing the queue
it "job in correct queue" do
described_class.perform_async
assert_equal :queuenamehere, described_class.queue
end
For testing the timing of the task
let(:time) { Time.zone.today + 6.hours).to_datetime } # define at the top of your rspec file
let(:scheduled_job) { described_class.perform_in(time, 'Awesome', true) } # define in the top of your rspec file
it 'occurs at expected time' do #define within a describe block
scheduled_job
assert_equal true, described_class.jobs.last['jid'].include?(scheduled_job)
expect(described_class).to have_enqueued_sidekiq_job('Awesome', true)
end
Full Example Test
require 'rails_helper' # include in your RSpec file
require 'sidekiq/testing' #include in your Rspec file
Sidekiq::Testing.fake! #include in your RSpec file
RSpec.describe ActionItemWorker, type: :worker do
let(:time) { (Time.zone.today + 6.hours).to_datetime }
let(:scheduled_job) { described_class.perform_at(time, 'Awesome', true) }
describe 'testing worker' do
it 'ActionItemWorker jobs are enqueued in the scheduled queue' do
described_class.perform_async
assert_equal :scheduled, described_class.queue
end
it 'goes into the jobs array for testing environment' do
expect do
described_class.perform_async
end.to change(described_class.jobs, :size).by(1)
described_class.new.perform
end
context 'occurs daily' do
it 'occurs at expected time' do
scheduled_job
assert_equal true, described_class.jobs.last['jid'].include?(scheduled_job)
expect(described_class).to have_enqueued_sidekiq_job('Awesome', true)
end
end
end
end
Running Your Tests
Run individual tests like this from your terminal: rspec path/to/file
You can also run tests manually by running: rails c
, then require 'sidekiq/testing'
. Your console should return true
, after running require sidekiq/testing
.
Then, you can run your WorkerNameHere.new.perform
to run your worker inline. Depending on your worker, you will get back a variety of responses. Expect whatever you are anticipating it to return here to be returned in the console.
Alternatively, you can also run WorkerNameHere.perform_in(5.seconds.from_now)
and the worker will perform in the future (exactly 5 seconds from now)! This will return a "jid" such as "9ef9392c92aee2540caf46ae". So, when you check your jobs array, created by the test environment, it should include your job.
To test your Sidekiq Worker jobs array, run WorkerNameHere.jobs
in terminal and see if it contains your job with your jid. If it does, then it was enqueued in Sidekiq to be run as a job.
Here is an example of the jobs array:
[{"class"=>"Worker",
"args"=>[],
"at"=>1559661046.951212,
"retry"=>false,
"queue"=>"scheduled",
"jid"=>"9ef9392c92aee2540caf46ae",
"created_at"=>1559661041.951413}]
Further Reading
For further reading on testing Sidekiq Workers in RSpec, please follow these links:
Header photo by Frank Wang on Unsplash