-
-
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_latermethod, wich is pointless.This kind of test shouldn't use the
perform_enqueued_jobsmethod 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
endIn 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 }
endThanks 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.
👍