How to check what is queued in ActiveJob using Rspec

后端 未结 7 1218
感动是毒
感动是毒 2021-01-31 08:33

I\'m working on a reset_password method in a Rails API app. When this endpoint is hit, an ActiveJob is queued that will fire off a request to Mandrill (our transactional email c

相关标签:
7条回答
  • 2021-01-31 08:45

    Testing Rails ActiveJob with RSpec

    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
    
    0 讨论(0)
  • 2021-01-31 08:50

    In a unit test, instead of checking what is queued one can also rely on ActiveJob working properly and just verify that it will be called by mocking its api.

     expect(MyJob).to receive(:perform_later).once 
     post :reset_password, user: { email: user.email }
    

    The creators of the ActiveJob have used the same techniques for their unit tests. See GridJob Testobject

    They create a testmock GridJob in their tests and override the perform method, so that it only adds jobs to a custom Array, they call JobBuffer. At the end they test, whether the buffer has jobs enqueued

    At a single place one can ofc also do an integrations test. The ActiveJob test_helper.rb is supposed to be used with minitest not with rspec. So you have to rebuild it's functionalitity. You can just call

    expect(ActiveJob::Base.queue_adapter.enqueued_jobs).to eq 1
    

    without requiring anything

    Update 1: As noticed within a comment. ActiveJob::Base.queue_adapter.enqueued_jobs works only by setting it the queue_adapter into test mode.

    # either within config/environment/test.rb
    config.active_job.queue_adapter = :test
    
    # or within a test setup
    ActiveJob::Base.queue_adapter = :test
    
    0 讨论(0)
  • 2021-01-31 08:50

    There is a new rspec extension which makes your life easier.

    require 'rails_helper'
    
    RSpec.describe MyController do
      let(:user) { FactoryGirl.create(:user) }
      let(:params) { { user_id: user.id } }
      subject(:make_request) { described_class.make_request(params) }
    
      it { expect { make_request }.to enqueue_a(RequestMaker).with(global_id(user)) }
    end
    
    0 讨论(0)
  • 2021-01-31 08:59

    In my opinion, ensure a job was enqueued when a request is performed is important. You can do it with the below solutions:

    Solution 1

    expect{ post your_api_here, params: params, headers: headers }
     .to have_enqueued_job(YourJob)
     .with(args)
    

    Solution 2

    expect(YourJob).to receive(:perform_later).once.with(args)
    post your_api_here, params: params, headers: headers
    
    
    0 讨论(0)
  • 2021-01-31 09:06

    Rspec 3.4 now has have_enqueued_job cooked in, which makes this a lot easier to test:

    it "enqueues a YourJob" do
      expect {
        get :your_action, {}
      }.to have_enqueued_job(YourJob)
    end
    

    it has other niceties for have_enqueued_job to allow you to check the argument(s) and the number of times it should be queued up.

    0 讨论(0)
  • 2021-01-31 09:09

    The accepted answer no longer works for me, so I tried Michael H.'s suggestion in the comments, which works.

    describe 'whatever' do
      include ActiveJob::TestHelper
    
      after do
        clear_enqueued_jobs
      end  
    
      it 'should email' do
        expect(enqueued_jobs.size).to eq(1)
      end
    end
    
    0 讨论(0)
提交回复
热议问题