Testing Rails ActiveJob

corymcdonald

Cory McDonald

Posted on July 21, 2020

Testing Rails ActiveJob

It can be a struggle to test 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 use MiniTest as my primary testing framework but all code that are shown in these examples should also work for RSpec.

Asserting that something is 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 sends correctly. 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

You can also 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 your application enqueues a lot of jobs then you'll likely want to be more specific with your tests. Consider the following which asserts a specific job is 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

If you have a bunch of jobs in your ActiveJob queue then you might want to clear them out.

You can use clear_enqueued_jobs which will reset the counter to 0. Later you can check assert_enqueued_jobs increased.

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. We do this by asserting the performed_jobs was equal to MAX_ATTEMPTS.

Asserting or checking the performed jobs

Finally you can assert the performed job has the arguments you expect.

assert_performed_with(job: RegisterUserWithSendGridJob) do
  patch(complete_signup_users_path, params: COMPLETE_SIGNUP_PARAMS)
end
💖 💪 🙅 🚩
corymcdonald
Cory McDonald

Posted on July 21, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related