升级到 Rails 6 后,我注意到默认邮件程序的
.deliver_later
的工作方式与 Rails 5 中不同。
配置:
config.active_job.queue_adapter = :inline
运行时
Mailer.register_email(...).deliver_later
- ActionMailer::Base.deliveries
中不存储任何内容。如果我运行 perform_enqueued_jobs
,这个数组就会被填满 - 看起来 queue_adapter = :inline
无法按照我期望的方式工作。
如果我运行
Mailer.send(...).deliver_now
那么 ActionMailer::Base.deliveries
就有适当的价值。
知道为什么会发生这种情况以及如何解决这个问题吗?
我在测试中遇到了同样的问题。在互联网上搜索没有结果,所以我开始尝试。
我尝试将发送邮件的调用方法封装在
assert_emails 1 do
Mailer.register_email(...).deliver_later
end
之后,
ActionMailer::Base.deliveries
已正确填充。
问题
问题在于 Rails 6 中添加的两行新代码(第 1 行和第 2 行), 基本上,在
here(在 RSpec 中)和 here (在 Minitest 中)定义的回调
before_setup
被覆盖(by this),从而强制 queue_adapter 成为 test 适配器 而不是那个由 config.active_job.queue_adapter
定义。
解决方法
因此,为了使用
queue_adapter
定义的 config.active_job.queue_adapter
并恢复 Rails 5 行为,我们可以执行如下操作。
# spec/support/active_job/test_helper.rb
module ActiveJob
module TestHelper
def before_setup
super
end
end
end
如果电子邮件的确切数量可以轻松更改,这是另一种选择:
assert_changes 'enqueued_jobs.size' do
# Some code that sends email with deliver_later
end
这允许您测试电子邮件是否已发送,但它忽略了确切的数量(这是
asserts_emails
方法的限制 - 除此之外,asserts_emails
方法很棒)。
我发现 enqueued_jobs
方法对于测试任何后台作业非常有帮助,包括 deliver_later
注意:上面的示例仅检查排队的作业列表是否已更改。如果您想更具体并检查队列是否已通过电子邮件更改,您应该这样做:
assert_changes 'enqueued_jobs.select {|job| job["job_class"] == "ActionMailer::MailDeliveryJob"}.size' do
# Some code that sends email with deliver_later
end
assert_enqueued_emails
在这种情况下也可能有帮助