如何测试ActiveJob回调?

时间:2018-02-20 07:27:46

标签: ruby-on-rails rspec delayed-job rails-activejob

我正在为学生构建电子邮件提醒功能。他们应该按照教师指定的时间间隔收到一封电子邮件,说明他们取得了多大进展。

我的方法是使用ActiveJob来安排发送电子邮件的作业,然后在执行作业时,我使用after_perform回调来安排下一个作业(取自this post)。这是什么样的:

class StudentReminderJob < ApplicationJob
  queue_as :default

  after_perform do |job|
    # (get user update frequency preference)

    self.class.set(wait: update_frequency).perform_later(job.arguments[0]) 
  end

  def perform(user)
    # Send email containing student stats information
    UserMailer.send_student_reminder_email(user)
  end
end

初始提醒集将由rake任务启动。

我的问题是:当试图用perform_enqueued_jobs测试上面的代码时,我似乎正在进行无限循环。这是我的考试:

require 'rails_helper'

describe StudentReminderJob, active_job: true, type: :job do
  include ActiveJob::TestHelper
  include ActiveSupport::Testing::TimeHelpers

  let(:user) { create :user }
  subject(:job) { described_class.perform_later(user) }

  it 'gets enqueued' do
    # Passes
    expect { job }.to have_enqueued_job(described_class)
  end

  it 'receives perform later with user and base URL' do
    # Passes (may be duplicatative)
    expect(StudentReminderJob).to receive(:perform_later).with(user)
    job
  end

  it 'calls UserMailer with #send_student_reminder_email when performed' do
    # Fails - (SystemStackError: stack level too deep)
    expect(UserMailer).to receive(:send_student_reminder_email)
    perform_enqueued_jobs { job }
  end

  after do
    clear_enqueued_jobs
    clear_performed_jobs
  end
end

第三个阻止失败,SystemStackError: stack level too deep。有没有办法只在队列中执行一个作业,并避免从回调中执行作业?

理想情况下,我希望扩展我的测试范围,以确保新作业在指定的日期和时间排队。

1 个答案:

答案 0 :(得分:1)

我怀疑这里的问题是perform_enqueued_jobs帮助程序尝试执行队列中的所有作业,直到该点为止,但是队列列表从未耗尽,因为每个作业都将另一个作业排队(因此循环)。

尝试一下,

  1. 首先,使用perform_later将作业放入队列。
  2. 从队列currently_queued_job = enqueued_jobs.first中获取作业详细信息。
  3. 调用perform_enqueued_jobs,但使用:only选项过滤/限制将要执行的作业。例如,
perform_enqueued_jobs(
  only: ->(job) { job['job_id'] == currently_queued_job['job_id'] }
)

这里是perform_enqueued_jobs的Rails documentation,提到:

:only:except选项接受Class,Class Array或Proc。通过Proc时,作业的实例将作为参数传递。