#Tech | 6 min read | Updated: 8/12/2022

Testing Sidekiq jobs: Which mode should I choose?

Updated: 8/12/2022
#Tech
6 min read

Sidekiq is a background job processor that helps Rails developers to increase the efficiency and responsiveness of an application.

The brilliant Sidekiq gem provides built-in tools for testing the various aspects of your worker’s lifecycle. The most important setting that you may choose as a developer is which testing mode to apply in a particular test. The documentation describes the behavior for both modes pretty clearly. But, besides that, it would be great to have an understanding of which aspects any particular mode suits best.

In this article, we will consider using Sidekiq for optimizing the Rails application performance. For you, we have prepared a brief guide on integrating Sidekiq with your project and testing Sidekiq worker in the different modes. This material will help you to evaluate each testing mode and understand how to work effectively with each of them.

Let’s dive in and try to sort this out.

Note: we’re going to use RSpec as a testing framework.

Using Sidekiq in Rails applications

Sidekiq is used for background processing of the tasks that can take a lot of time. This increases the responsiveness of the application, allowing user not to have to wait for the work to be completed.

This is very convenient for processing the complex tasks (for example, scanning the data from a big document and recording this to the database). When the tasks are launched they are queued. For example, if a user sends a letter from a Rails application that uses Sidekiq, there is no necessity to wait for the actual completion of the tasks. The user sends the letter, Sidekiq gets the task for sending and the browser displays the message: “Sending the letter”. Meanwhile, Sidekiq sends the letter in the background mode.

Further we are going to operate with two common Sidekiq terms: job and worker. For your convenience, let’s define their meanings.

A Sidekiq job is an operation that is processed in the background mode. The gem manages the queue of jobs in the database as JSON data sets. A worker is a Ruby class responsible for executing a job. When Sidekiq is ready to start job processing, the responsible worker is launched.

How to set up Sidekiq for your project

Sidekiq is very easy to set up – it is enough just to add the gem to the Gemfile and run installation of the new gem in Rails Console:

gem 'sidekiq'
bundle install

Then, specify the queue server in config/application.rb and create a task:

config.active_job.queue_adapter = :sidekiq
rails generate job Some

This will generate the file app/jobs/some_job.rb with the following contents:

class SomeJob < ApplicationJob
queue_as :default


def perform(*args)
# Do something later
end
end

To work with Sidekiq, we will need the set up and launched redis-server. For example, on Ubuntu 14.04, it is easy to set up with sudo apt-get install redis-server command. Having launched Sidekiq in the development environment, you are now ready to work.

Types of testing Sidekiq jobs

Fake it until you make it

Sidekiq::Testing.fake! is the default testing mode. When used, Sidekiq pushes all jobs queueing up into the internal array for each worker class.

require "sidekiq/testing" # you would likely add this to your rails_helper.rb


expect { MyWorker.perform_async(:my_arg) }.to change { MyWorker.jobs.size }.by(1)

Your jobs get queued but are not actually executed. To execute them, you need to drain the queues:

Sidekiq::Worker.drain_all

Unfortunately, this means that you would have to repeat the Sidekiq::Worker.drain_all snippet before each test in your worker’s set of examples:

describe MyWorker do
it "does something useful" do
MyWorker.perform_async(:my_arg)
Sidekiq::Worker.drain_all
# expect(...).to ...
end


it "does something useful again" do
MyWorker.perform_async(:my_arg, :additional_arg)
Sidekiq::Worker.drain_all
# expect(...).to ...
end
end

Also, the control exerted by draining all of the queues after each example seems a bit too inspecific for me. What if we could execute each “worker” line of code for real without any additional hassle or messing with draining queues? The next section describes the Sidekiq::Testing mode that works exactly this way.

To summarize the fake mode, its purpose is to test the actual behavior of the “worker’s” performance and how correctly it executes. In contrast, testing to see if the worker queued up should just be a sanity check and could be extracted into a shared example:

shared_examples "a worker with args of" do |*args|
it "gets enqueued" do
expect { described_class.perform_async(*args) }.to change { described_class.jobs.size }.by(1) }
end
end


describe MyWorker do
it_behaves_like "a worker with args of", :my_arg
end

Getting real

The Sidekiq::Testing.inline! testing mode executes the jobs immediately when they are placed in the queue. In my opinion, this should be the default testing mode for Sidekiq. Of course, you can test your workers directly:

worker = MyWorker.new
worker.perform(:my_arg)

But this makes your test invocations inconsistent compared to the invocations in real code (perform_async).

With Sidekiq inline mode as the default, your worker’s logic is tested right out of the box. This will cause you to think about the dependencies of your workers to be able to mock them effectively and even make expectations for calls to them.

# implementation
class DeleteFromRemoteApiWorker
include Sidekiq::Worker

def perform(item_ids)
ApiWrapper.delete_items(item_ids) # dependency
end
end


# test
describe DeleteFromRemoteApiWorker do
let(:items) do
# ...
end

it "delegates the work to the API wrapper as expected" do
allow(ApiWrapper).to receive(:delete_items)
item_ids = items.map(&:id)

described_class.perform_async(item_ids)


expect(ApiWrapper).to(
have_received(:delete_items).with(item_ids)
)
end
end

To simplify the usage for the cases where you still need fake mode, I suggest adding the following snippet to your rails_helper.rb:

require "sidekiq/testing"
Sidekiq::Testing.inline!

config.around(type: :worker) do |example|
if example.metadata[:sidekiq_fake] == true
Sidekiq::Testing.fake! { example.run }
end

# and its usage
# (actually a good example of when you just need to test if that job has queued up)


describe "rake my_project:my_task" do
it "adds new jobs digest job to the queue", :sidekiq_fake do
task.execute # a part of the custom functionality that executes the Rake task mentioned in the example description
expect(MyWorker).to have_enqueued_sidekiq_job
end
end

Bonus: make your worker tests read more naturally

But wait a minute! What was that have_enqueued_sidekiq_job?

In order to test Sidekiq jobs more naturally, I recommend using the beautiful rspec-sidekiq gem, which contains plenty of matchers with “speaking” names. Go on and discover them!

Conclusion

Having read this article, you are now aware of the different modes of Sidekiq testing.

During the everyday testing work, you always test your application at the unit level. Later, you test how it interacts with the other parts of the program. Finally, you test the integration of the app with the database and the other services. In this way, you also should also work with Sidekiq to:

  • use unit tests to evaluate the worker behavior;
  • test interaction of your jobs while testing the interaction of the different parts of your app;
  • test workers inline when it is necessary to test the performance of the overall system.

Happy Sidekiq testing!

How useful was this post?

Click on a star to rate it!

Average rating / 5. Vote count:

No votes so far! Be the first to rate this post.

Share:

Subscribe
Notify of
guest

1 Comment
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Recommended articles

Today, most companies want to implement their product on time and within a specified budget. However, it is almost impossible to achieve this without developing a product development strategy. All new projects start with an…

#Real Estate 18 min

Digital transformation in real estate has swept many business owners with new standards and AI development. As customer expectations change, no business wants to be left behind. 66% of customers want solutions to understand their…

How long does it take to make an app? – that’s what the IBM Simon smartphone creators asked themselves back in 1992. Since it was the first experience ever creating an app, nobody answered.  As…

Scale your team with us

Drive your business with our dedicated developers

    *By submitting this form, you agree to our Terms of Use and Privacy Policy.

    Alex, VP of Client Engagement
    alex@sloboda-studio.com