How to test Sidekiq scheduler cron jobs



Published on by



2 minutes reading

The sidekiq-scheduler gem is an extension to sidekiq that pushes jobs in a scheduled way, mimicking cron utility.

It is a really usefull gem I like to use on every project that requires recurring jobs. It is also quite easy to set up once installed in your app. Most of the time, I require the gem in a sidekiq.rb initializer so every jobs has access to this feature.

Once your set up is complete, you will have the ability to add schedules in your config/sidekiq.yml file.

# config/sidekiq.yml example

  cron: '0 * * * * *'  # Runs once per minute, could also be 'every: 1 minutes'
  class: HelloWorld

I really put an emphasis to test every feature that I code in an app. This article is about implementing the corresponding tests for the :schedule: part on this file. Imagine that you change the name of a recurring job and forget to reflect the change in this file? Or you messed up your cron syntax? Well you might not see it after some time, implementing automatic testing with RSpec will remedy to that.

There are 3 things I would like to test in the example above:

- The cron syntax should be correct

- The job the task is calling should exist

- The task name should be similar to the job name

Testing the cron syntax can be achieved thanks to 'fugit' which is a dependency of sidekiq-scheduler that analyze cron syntax, the 2 remaining things to test are pretty straightforward.

It basically looks like that:

# Sidekiq-scheduler uses 'fugit' dependency under the hood to evaluate cron schedules
require "fugit"

RSpec.describe "Sidekiq Scheduler" do
 sidekiq_file = File.join(Rails.root, "config", "sidekiq.yml")
 scheduled_jobs = YAML.load_file(sidekiq_file)[:schedule]

 scheduled_jobs.each do |task_name, task_config|
  job_class = task_config["class"]
  cron = task_config["cron"] || task_config["every"] || task_config["at"] 
      || task_config["in"]

  describe "#{task_name}" do

   it "has a correct cron syntax" do
    expect { Fugit.do_parse(cron) }.not_to raise_error

   it "is calling an existing job (#{job_class})" do
    expect { job_class.constantize }.not_to raise_error

   it "has a correct name related to the called job" do
    expect(task_name + "_job").to eq(job_class.underscore)


- A nice article that inspired me for setting up these tests

My last articles