延迟的工作没有在rspec中被处理

35
我正在尝试运行自定义延迟作业(GetPage::GetPageJob)的rspecs,但我遇到了问题。运行它们时,该作业会被成功排队(也就是说,已经成功插入到delayed_jobs表中),但作业工作者没有处理该作业。确实,在第一个终端中启动"rake jobs:work RAILS_ENV=test",在第二个终端中运行specs之后,我没有看到来自第一个终端的作业工作者的任何输出。另一方面,如果我通过"script/console test"将它们排队,则可以成功处理这些作业。所以我有点困惑。对于规范和脚本/控制台,我用于排队作业的代码行是:
Delayed::Job.enqueue GetPage::GetPageJob.new("http://cnn.com")
任何想法?
4个回答

98

在 RSpec 中测试队列中的 Delayed::Job 任务最简单的方法是实时运行它们。只需将以下代码添加到您的 RSpec 测试中:

Delayed::Worker.delay_jobs = false

这将导致您的作业在入队时立即处理,而不是在单独的线程中处理。这通常适用于测试,因为它是确定性的。

两个注意事项

  • 如果您想测试时间错误、竞争条件等,这种方法将无济于事(因为作业与 RSpec 在同一线程中处理)

  • 当前版本的 delayed_job(2.1.4)存在一个小 bug,即当 Delayed::Worker.delay_jobs 设为 false 时,回调钩子(enqueue、before、success、error、failure)不会被调用。

两种解决方法

如果您需要测试回调钩子,则我知道两种解决方法:

  • 从 Github 上获取最新的主分支。(我没有尝试过,因为我需要稳定的版本)

  • 不要设置 Delayed::Worker.delay_jobs = false,而是在测试代码中显式调用 DJ 的运行机制,如下所示:

    successes, failures = Delayed::Worker.new.work_off

这将处理作业队列中的任何内容(同样在 RSpec 测试的同一线程中),并返回两个数字:成功的作业数和失败的作业数。我目前使用此方法,它可以满足我的所有需求。


6
你的回答非常聪明、全面且文档化得很好 : )。谢谢,你让我的一天变得更美好了 : )。 - Dorian
@oma: 或许我误解了你的意思,但是 [successes, failures] 的返回值会考虑 :attempts 参数:只有当 :attempts 的次数超过限制时,任务才会真正失败。 - fearless_fool
2
成功和失败的赋值语句有语法错误,赋值语句中应该没有 [ ]。 successes, failures = Delayed::Worker.new.work_off - dB.
@dblock:没错,我正在编辑回复以修复它。(真奇怪之前没有人评论!) - fearless_fool
可能值得提到的是回调函数可能存在的问题。 - brntsllvn
显示剩余2条评论

3
过去,我尝试过对逻辑-延迟作业-执行作业进行端到端测试,但这太多了。我认为,与其使用RSpec测试整个流程,不如专注于测试每个方面。
因此,测试作业是否被插入。然后,进行另一个测试,测试执行作业时应该发生什么。
或者,模拟延迟作业,以便当您将作业加入队列时,它立即执行。

我发现你最后一句话非常有用;我只需要这样做,例如 UserMailer.stub(delay: UserMailer) 或者 obj.stub(delay: obj),我的测试就可以愉快地进行了。虽然在配置文件中使用 Delayed::Worker.delay_jobs = !Rails.env.in?(['development', 'test']) 这个建议也可以解决问题,但是我有一堆测试是针对延迟任务本身的,我现在不想更新它们。谢谢! - aec

3
您需要在测试中启动工作进程而不是从另一个进程中启动。尝试使用以下方法:
worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
worker.work_off

1

我使用配置选项实时运行作业:

# config/initializers/delayed_job_config.rb
Delayed::Worker.delay_jobs = !Rails.env.test?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接