在 rspec 中使用 ActiveJob 执行挂起的作业

Posted

技术标签:

【中文标题】在 rspec 中使用 ActiveJob 执行挂起的作业【英文标题】:Execute pending job with ActiveJob in rspec 【发布时间】:2015-03-07 17:23:56 【问题描述】:

我有这段代码可以用 Rspec 测试 ActiveJob 和 ActionMailer 我不知道如何真正执行所有排队的工作

describe 'whatever' do
  include ActiveJob::TestHelper

  after do
    clear_enqueued_jobs
  end  

  it 'should email' do
    expect(enqueued_jobs.size).to eq(1)
  end
end

【问题讨论】:

也许这会有所帮助medium.com/@chuckjhardy/… 【参考方案1】:

这是我解决类似问题的方法:

# rails_helper.rb
RSpec.configure do |config|
  config.before :example, perform_enqueued: true do
    @old_perform_enqueued_jobs = ActiveJob::Base.queue_adapter.perform_enqueued_jobs
    @old_perform_enqueued_at_jobs = ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs
    ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
    ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
  end

  config.after :example, perform_enqueued: true do
    ActiveJob::Base.queue_adapter.perform_enqueued_jobs = @old_perform_enqueued_jobs
    ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = @old_perform_enqueued_at_jobs
  end
end

然后在规范中我们可以使用:

it "should perform immediately", perform_enqueued: true do
  SomeJob.perform_later  
end

【讨论】:

很好的答案。我将此添加到规范/支持中的文件中。似乎这对于在集成测试中测试电子邮件值是 100% 必要的。 这真的是确保针对特定集成测试内联执行作业的唯一方法吗?让我大吃一惊的是,没有更简单的方法可以做到这一点。 @cgat 否 - 您可以将 "ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true" 放在 before 块中,您的排队作业将在您的示例中及时执行。【参考方案2】:

正确的测试方法是检查排队作业的数量,如您的示例所示,然后分别测试每个作业。如果你想做集成测试,你可以试试 perform_enqueued_jobs helper:

describe 'whatever' do
  include ActiveJob::TestHelper

  after do
    clear_enqueued_jobs
  end  

  it 'should email' do
    perform_enqueued_jobs do
      SomeClass.some_action
    end
  end

end

见ActiveJob::TestHelper docs

【讨论】:

有人可以举一个不那么做作的例子来说明接受参数的邮件会是什么样子吗?我似乎无法让它与OrderMailer.receipt_email(order.id) 之类的东西一起使用。 确保在测试邮件程序并尝试解雇工作时使用 Deliver_now 或 Deliver_later 方法。【参考方案3】:

只是结合了所有最好的部分,+包括 sidekiq:

spec/support/perform_jobs.rb

require 'sidekiq/testing'

RSpec.configure do |config|
  Sidekiq::Testing.fake!

  config.around(:each, perform_jobs: true) do |example|
    Sidekiq::Testing.inline! do
      queue_adapter = ActiveJob::Base.queue_adapter
      old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
      old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
      queue_adapter.perform_enqueued_jobs = true
      queue_adapter.perform_enqueued_at_jobs = true
      example.run
    ensure
      queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs
      queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs
    end
  end

end

spec/some_spec.rb

it 'works', perform_jobs: true do
  ...
end

【讨论】:

以上是关于在 rspec 中使用 ActiveJob 执行挂起的作业的主要内容,如果未能解决你的问题,请参考以下文章

使用 RSpec 测试 DeserializationError

rspec rails testing:如何强制 ActiveJob 作业内联运行某些测试?

集成测试ActionMailer和ActiveJob

如何告诉 rspec 在没有挂起测试输出的情况下运行?

在 ActiveJob 中,如何捕获任何异常

使用 Sidekiq 进行活动作业并获取 ActiveJob::DeserializationError