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