Testing ActiveJob with Rails 6

It can be a struggle to tests Rails sometimes. Documentation surrounding the Rails ActiveJob module isn’t the best. This post will walk you through some snippets and how you can test.

I primarily use Minitest as it was the testing framework set up in the project I work in but all code that works in MiniTest should also work for RSpec.

Asserting that something was enqueued in a Rails Test#

test "sends one email and refreshes auth token" do
  assert_enqueued_jobs(1) do
    # Sends off an email
    MailerServices::VerifyEmailEmailer.new(publisher: publisher).execute
  end
end

Assert an email is enqueued#

Another option is to check to see if an email is sent. You can view all the Test Helpers with ActionMailer::TestHelper

def test_emails
  assert_emails 0
  ContactMailer.welcome.deliver_now
  assert_emails 1
  ContactMailer.welcome.deliver_now
  assert_emails 2
end

Alternatively you can check that a specific email was enqueued

def test_email_in_block
  assert_enqueued_email_with ContactMailer, :welcome do
    ContactMailer.welcome.deliver_later
  end
end

Test a specific job was enqueued#

If you have a complex application which is enqueuing a lot of jobs then you’ll want to make sure the job your testing was enqueued

test "create launches EnqueueUsersForPayoutJob for administrators" do
  sign_in users(:admin)

  assert_enqueued_with(job: EnqueueUsersForPayoutJob) do
    post admin_payout_reports_path
  end
end

You can even pass in arguments, so that you can ensure that something is valid

# Pull channel from fixtures
channel = channels(:unverified)

assert_enqueued_with(job: VerifySiteChannel, args: [{ channel_id: channel.id }]) do
  # Execute job that enqueued VerifySiteChannel.
  EnqueueSiteChannelVerifications.perform_now
end

Clear the existing jobs or queue#

Sometimes you’ll have a bunch of items in your ActiveJob queue but you only want to check that a job was enqueued after your code.

test "approves channels that have waited the timeout period" do
  clear_enqueued_jobs
  clear_performed_jobs

  travel(Channel::CONTEST_TIMEOUT + 1.minute) do
    assert_enqueued_jobs 0
    Channels::TransferChannelsJob.perform_now

    assert_enqueued_jobs 1
  end
end

Asserting how many jobs were performed#

In the above example I’m asserting that jobs were enqueued, but what about jobs that were performed?

Consider the following code:

assert_performed_jobs 0
perform_enqueued_jobs(only: Promo::RegisterChannelForPromoJob)
assert_performed_jobs Promo::AssignPromoToChannelService::MAX_ATTEMPTS

We assert that there was 0 performed jobs. Then we execute only the job that we want to perform. Finally we assert that our retry logic in our job was valid by asserting the performed_jobs was equal to MAX_ATTEMPTS.

Asserting or checking the performed jobs#

One thing that’s helpful is checking the performed job was enqueued with the arguments you expected

assert_performed_with(job: RegisterUserWithSendGridJob) do
  patch(complete_signup_users_path, params: COMPLETE_SIGNUP_PARAMS)
end