Testing sidekiq perform_in with RSpec 3
RSpec 3 and sidekiq 3.2.1. And I have installed sidekiq and rspec-sidekiq correctly.
Let's say I have a worker named WeatherJob
that will change the weather status from sunny
to rainy
:
class WeatherJob
include Sidekiq::Worker
def perform record_id
weather = Weather.find record_id
weather.update status: 'rainy'
end
end
I am using this worker as follows:
WeatherJob.perform_in 15.minutes, weather.id
...
In the spec, I use Timecop to determine the time:
require 'rails_helper'
describe WeatherJob do
let(:weather) { create :weather, status: 'sunny' }
let(:now) { Time.current }
it 'enqueue a job' do
expect {
WeatherJob.perform_async weather.id
}.to change(WeatherJob.jobs, :size).by 1
end
context '15 mins later' do
before do
Timecop.freeze(now) do
Weather.perform_in 15.minutes, weather.id
end
end
it 'update to rainy' do
Timecop.freeze(now + 16.minutes) do
expect(weather.status).to eq 'rainy'
end
end
end
end
I saw that there is work in the array Weather.jobs
. And the time is correct 16 minutes after. But it didn't do the job? Any tips? Thank!
source to share
Sidekiq has three test modes: disabled, fake, and built-in. The default is fake, which just puts all jobs in the job array and the behavior you see. Inline mode starts the job immediately, rather than forcing it to run.
To force Sidekiq to run an inline job during a test, wrap the test code in a block Sidekiq::Testing.inline!
:
before do
Sidekiq::Testing.inline! do
Timecop.freeze(now) do
Weather.perform_in 15.minutes, weather.id
end
end
end
For more information on testing Sidekiq, see the official testing wiki page .
source to share
If you want to test an assignment whether it should run after 15 minutes or not, you must split the test cases into two parts. In the first part, you have to check if it will insert a job that will be active for 15 minutes (using mocks). The second part is whether the task was done correctly or not.
source to share
Do this in two steps. First check that the job was scheduled, then run the job in strict mode without delay. Here's an example
it "finishes auction (async)" do
auction = FactoryGirl.create(:auction)
auction.publish!
expect(AuctionFinishWorker).to have_enqueued_sidekiq_job(auction.id).at(auction.finishes_at)
end
it "finishes auction (sync)" do
auction = FactoryGirl.create(:auction)
auction.publish!
Sidekiq::Testing.inline! do
AuctionFinishWorker.perform_async(auction.id)
end
auction.reload
expect(auction).to be_finished
end
have_enqueued_sidekiq_job
the method comes from the rspec-sidekiq gem. They are actively developing in the industry develop
. Make sure you enable it like this.
gem 'rspec-sidekiq', github: "philostler/rspec-sidekiq", branch: "develop"
source to share