Testing Sidekiq in Ruby on Rails: A Comprehensive Guide
Introduction
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!
Config Sidekiq in a Ruby on Rails Application
- Add sidekiq to the Gemfile.
# 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
Generate a New Job
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
Sidekiq testing
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.
Fake Testing
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
Testing with Disable Mode
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
Tips and Sidekiq Web UI
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!
Resources
https://github.com/sidekiq/sidekiq/wiki/Testing
https://gist.github.com/mateuszbialowas/b9944a3c0a11c80e25aceb4e0483afe1
Subscribe to my newsletter
Read articles from Mateusz Białowąs directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by