-
-
Save ChuckJHardy/10f54fc567ba3bd4d6f1 to your computer and use it in GitHub Desktop.
class MyJob < ActiveJob::Base | |
queue_as :urgent | |
rescue_from(NoResultsError) do | |
retry_job wait: 5.minutes, queue: :default | |
end | |
def perform(*args) | |
MyService.call(*args) | |
end | |
end | |
require 'rails_helper' | |
RSpec.describe MyJob, type: :job do | |
include ActiveJob::TestHelper | |
subject(:job) { described_class.perform_later(123) } | |
it 'queues the job' do | |
expect { job } | |
.to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(1) | |
end | |
it 'is in urgent queue' do | |
expect(MyJob.new.queue_name).to eq('urgent') | |
end | |
it 'executes perform' do | |
expect(MyService).to receive(:call).with(123) | |
perform_enqueued_jobs { job } | |
end | |
it 'handles no results error' do | |
allow(MyService).to receive(:call).and_raise(NoResultsError) | |
perform_enqueued_jobs do | |
expect_any_instance_of(MyJob) | |
.to receive(:retry_job).with(wait: 10.minutes, queue: :default) | |
job | |
end | |
end | |
after do | |
clear_enqueued_jobs | |
clear_performed_jobs | |
end | |
end | |
# As of RSpec 3.4.0 we now have #have_enqueued_job | |
# https://www.relishapp.com/rspec/rspec-rails/v/3-5/docs/matchers/have-enqueued-job-matcher | |
RSpec.describe MyJob, type: :job do | |
subject(:job) { described_class.perform_later(key) } | |
let(:key) { 123 } | |
it 'queues the job' do | |
expect { job }.to have_enqueued_job(described_class) | |
.with(key) | |
.on_queue("urgent") | |
end | |
end |
subject(:job) { described_class.perform_later(123) }
it 'queues the job'
it 'executes perform'
Those two specs don't test your job. They test the ActiveJob
's #perform_later
method, wich is pointless.
This kind of test shouldn't use the perform_enqueued_jobs
method at all. It's for higher level tests.
๐
subject(:job) { described_class.perform_later(123) } it 'queues the job' it 'executes perform'
Those two specs don't test your job. They test the
ActiveJob
's#perform_later
method, wich is pointless.This kind of test shouldn't use the
perform_enqueued_jobs
method at all. It's for higher level tests.
@chumakoff I think these tests are useful. Let's say I have a job like this
def perform
User.where(...).find_each do |user|
UpdateSomething.new(user).call
end
end
In the test, I want to stub the internals of UpdateSomething
and I want to test whether the query is correct, so whether it calls the service for each user found by the query. executes perform
does that
before { allow_any_instance_of(UpdateSomething).to receive(:call) }
it 'executes perform' do
expect_any_instance_of(UpdateSomething).to receive(:call) # if I expect only one call
perform_enqueued_jobs { job }
end
Thanks for the gist @ChuckJHardy
@ToTenMilan I agree with you, except the test should have a proper description.
Now the description is it 'executes perform'
. It is pointless to check whether :perform_later
executes :perform
since it is the ActiveJob's code. A proper description would be: it 'calls a service'
.
The it 'queues the job'
example has both pointless description and implementation. It is not needed to check if :perform_later
enqueues the job, for the same reason.
@ChuckJHardy Thanks. It does make sense to
trust the internals
๐