如何测试 ActiveJob 回调?
How to test an ActiveJob callback?
我正在为学生构建电子邮件提醒功能。他们应该会在导师指定的时间间隔内收到一封电子邮件,表明他们取得了多少进步。
我的做法是使用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
最初的一组提醒将由佣金任务启动。
我的问题是:当我尝试用 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
第三个 it 块失败 SystemStackError: stack level too deep
。有没有办法只执行队列中的一个作业,避免从回调中执行作业?
理想情况下,我想扩大我的测试范围,以确保在给定的日期和时间排队新作业。
我怀疑这里的问题是 perform_enqueued_jobs
助手试图执行队列中的所有作业直到那个点,但是队列列表永远不会用完,因为每个作业都会排队另一个作业(因此循环).
试试这个,
- 首先,将作业放入
perform_later
的队列中。
- 从队列
currently_queued_job = enqueued_jobs.first
中获取 parent 作业详细信息。
- 调用
perform_enqueued_jobs
但使用 :only
选项 filter/limit 将执行的作业。例如,
perform_enqueued_jobs(
only: ->(job) { job['job_id'] == currently_queued_job['job_id'] }
)
这是 perform_enqueued_jobs
的 Rails documentation,提及:
:only
and :except
options accepts Class, Array of Class or Proc. When passed a Proc, an instance of the job will be passed as argument.
我正在为学生构建电子邮件提醒功能。他们应该会在导师指定的时间间隔内收到一封电子邮件,表明他们取得了多少进步。
我的做法是使用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
最初的一组提醒将由佣金任务启动。
我的问题是:当我尝试用 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
第三个 it 块失败 SystemStackError: stack level too deep
。有没有办法只执行队列中的一个作业,避免从回调中执行作业?
理想情况下,我想扩大我的测试范围,以确保在给定的日期和时间排队新作业。
我怀疑这里的问题是 perform_enqueued_jobs
助手试图执行队列中的所有作业直到那个点,但是队列列表永远不会用完,因为每个作业都会排队另一个作业(因此循环).
试试这个,
- 首先,将作业放入
perform_later
的队列中。 - 从队列
currently_queued_job = enqueued_jobs.first
中获取 parent 作业详细信息。 - 调用
perform_enqueued_jobs
但使用:only
选项 filter/limit 将执行的作业。例如,
perform_enqueued_jobs(
only: ->(job) { job['job_id'] == currently_queued_job['job_id'] }
)
这是 perform_enqueued_jobs
的 Rails documentation,提及:
:only
and:except
options accepts Class, Array of Class or Proc. When passed a Proc, an instance of the job will be passed as argument.