Testing Sidekiq in Ruby on Rails: A Comprehensive Guide

Search for a command to run...

No comments yet. Be the first to comment.
Recently, I needed to implement a search feature for tags that are attached to specific owners using the acts_as_taggable_on gem in a Rails project. Since we use Ransack for searching, I wanted to integrate both tools. However, the standard document...

Recently, while experimenting with Stripe, I noticed that objects have IDs or identifiers with prefixes. Below, I've listed a few examples. You can find more in this gist: https://gist.github.com/fnky/76f533366f75cf75802c8052b577e2a5 PrefixDescri...

Introduction Ensuring stability and consistency in tests is very important. One key aspect of testing is the ability to avoid flaky tests, which are tests that do not pass each time they are run. Navigating Through Flaky Tests Sometimes, the ordering...

TL;DR post searches_url, params: { search: invalid_attributes }, as: :turbo_stream I have recently implemented CRUD(Create, Read, Update, Delete) operations using Rails 7. There are multiple methodologies for creating and updating records. One such...

Sidekiq is a powerful tool for handling asynchronous jobs in Ruby. It can be easily integrated with Ruby on Rails applications to streamline background tasks. With Ruby on Rails, there are two main options for using Sidekiq:
Integrate Sidekiq with Active Job and utilize the helpers provided by Rails
Use plain Sidekiq without Active Job
In this article, we will focus on using Sidekiq without Active Job, which can be 2-20 times faster than using it with Active Job. We will cover how to configure Sidekiq with Ruby on Rails application, how to generate jobs, and how to test them. Let's get started!
# Gemfile
gem 'sidekiq'
group :test do
gem 'rspec-sidekiq'
end
2. Configure the queue adapter for Rails:
# config/application.rb
config.active_job.queue_adapter = :sidekiq
With this configuration, Sidekiq is now set up for your Ruby on Rails application. Next, let's generate our first job:
rails generate sidekiq:job example
We will create a simple service that runs a job asynchronously and a job that updates an employee's position:
# app/services/example.rb
class Example
def initialize(employee_id)
@employee_id = employee_id
end
def call
ExampleJob.perform_async(@employee_id)
end
end
# app/sidekiq/example_job.rb
class ExampleJob
include Sidekiq::Job
def perform(employee_id)
employee = Employee.find(employee_id)
employee.update!(position: 'CEO')
end
end
With Sidekiq, we have three strategies for testing our code:
Fake mode (default): Jobs are pushed into an array instead of Redis.
Inline mode: Code is executed synchronously.
Disable mode: Jobs are pushed into Redis.
For service testing, I recommend using the default fake mode. For job testing, I recommend using inline mode, as it tests the exact behavior of the worker.
subject(:job) { ExampleJob.perform_async(employee_id) }
it 'queues the job' do
expect { job }.to change(Sidekiq::Queues['default'], :size).by(1)
end
it 'queues the job2' do
expect { job }.to change(ExampleJob.jobs, :size).by(1)
end
it 'queues the job3 with rspec-sidekiq helper' do
job
expect(described_class).to have_enqueued_sidekiq_job(employee.id)
end
Now, let's execute the code and check if the worker's code is working as expected. To do this, we will use the drain method, which processes all jobs:
expect do
job
described_class.drain
end.to change { employee.reload.position }.from('resource').to('CEO')
We can also execute the job using the perform_inline method, which will execute the code synchronously:
it 'raise errors2' do
expect { described_class.perform_inline(employee_id) }.to raise_error(ActiveRecord::RecordNotFound)
end
Lastly, we can use the RSpec hook with custom metadata:
it 'raise errors3', :inline_sidekiq_testing do
expect { job }.to raise_error(ActiveRecord::RecordNotFound)
end
---
rails_helper.rb
config.around(:each, :inline_sidekiq_testing) do |example|
Sidekiq::Testing.inline! do
example.run
end
end
This mode can be useful for integration tests when we want to check if the job was queued in Redis.
it 'enqueue job' do
Sidekiq::Testing.disable! do
expect { service }.to change { Sidekiq::Queue.new.size }.by(1)
end
end
You can refactor the above code as follows:
config.around(:each, :disable_sidekiq_testing) do |example|
Sidekiq::Testing.disable! do
example.run
end
end
it 'enqueue job2', :disable_sidekiq_testing do
expect { service }.to change { Sidekiq::Queue.new.size }.by(1)
end
You can also test it in this way:
it 'enqueue job3', :disable_sidekiq_testing do
expect { service }.to change {
Sidekiq::Queue.new.select do |job|
job.klass == 'ExampleJob'
job.args == [employee_id_param]
job.queue == 'default'
end.size
}.by(1)
end
At the end of this guide, I want to introduce you to the Sidekiq Web UI. You can implement it by adding the following your routes:
# config/routes.rb
require 'sidekiq/web'
Rails.application.routes.draw do
mount Sidekiq::Web => '/sidekiq'
root 'pages#home'
end
With the Sidekiq Web UI, you can monitor the status of your jobs and gain insights into the performance of your background tasks.

Now you have a comprehensive guide on how to test Sidekiq in a Ruby on Rails application. Good luck and happy testing!
https://github.com/sidekiq/sidekiq/wiki/Testing
https://gist.github.com/mateuszbialowas/b9944a3c0a11c80e25aceb4e0483afe1