Ruby-on-rails 如何使用 Rspec 检查 ActiveJob 中排队的内容

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26274954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:57:19  来源:igfitidea点击:

How to check what is queued in ActiveJob using Rspec

ruby-on-railsrubyrspecrails-activejob

提问by mylescc

I'm working on a reset_password method in a Rails API app. When this endpoint is hit, an ActiveJob is queued that will fire off a request to Mandrill (our transactional email client). I'm currently trying to write the tests to ensure that that the ActiveJob is queued correctly when the controller endpoint is hit.

我正在 Rails API 应用程序中使用 reset_password 方法。当这个端点被击中时,一个 ActiveJob 排队,它将向 Mandrill(我们的交易电子邮件客户端)发出请求。我目前正在尝试编写测试以确保在命中控制器端点时 ActiveJob 正确排队。

def reset_password
  @user = User.find_by(email: params[:user][:email])
  @user.send_reset_password_instructions
end

The send_reset_password_instructions creates some url's etc before creating the ActiveJob which's code is below:

send_reset_password_instructions 在创建 ActiveJob 之前创建了一些 url 等,其代码如下:

class SendEmailJob < ActiveJob::Base
  queue_as :default

  def perform(message)
    mandrill = Mandrill::API.new
    mandrill.messages.send_template "reset-password", [], message
  rescue Mandrill::Error => e
    puts "A mandrill error occurred: #{e.class} - #{e.message}"
    raise
  end
end

At the moment we are not using any adapters for the ActiveJob, so I just want to check with Rspec that the ActiveJob is queued.

目前我们没有为 ActiveJob 使用任何适配器,所以我只想使用 Rspec 检查 ActiveJob 是否已排队。

Currently my test looks something like this (I'm using factory girl to create the user):

目前我的测试看起来像这样(我使用 factory girl 创建用户):

require 'active_job/test_helper'

describe '#reset_password' do
  let(:user) { create :user }

  it 'should create an ActiveJob to send the reset password email' do
    expect(enqueued_jobs.size).to eq 0
    post :reset_password, user: { email: user.email }
    expect(enqueued_jobs.size).to eq 1
  end
end

Everything works in reality, I just need to create the tests!

一切都在现实中工作,我只需要创建测试!

I'm using ruby 2.1.2 and rails 4.1.6.

我正在使用 ruby​​ 2.1.2 和 rails 4.1.6。

I can't see any documentation or help anywhere on the web on how to test on this so any help would be greatly appreciated!

我在网络上的任何地方都看不到有关如何对此进行测试的任何文档或帮助,因此将不胜感激!

回答by Josh Smith

The accepted answer no longer works for me, so I tried Michael H.'s suggestion in the comments, which works.

接受的答案不再适合我,所以我在评论中尝试了 Michael H. 的建议,这很有效。

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

回答by dre-hh

You really don't need to test ActiveJob functionality. Just test that your code calls it properly by stubbing it out

您真的不需要测试 ActiveJob 功能。只需通过存根测试您的代码是否正确调用它

 expect(MyJob).to receive(:perform_later).once 
 post :reset_password, user: { email: user.email }

The creators of the ActiveJob have used the same techniques for their unit tests. See GridJob Testobject

ActiveJob 的创建者在他们的单元测试中使用了相同的技术。参见GridJob 测试对象

They create a testmock GridJob in their tests and override the perform method, so that it only adds jobs to a custom Array, they call JobBuffer. At the end they test, whether the buffer has jobs enqueued

他们在他们的测试中创建了一个 testmock GridJob 并覆盖了 perform 方法,这样它只会将作业添加到自定义数组中,他们调用JobBuffer。最后他们测试缓冲区是否有作业入队

However if nothing can't stop you of doing a full integration test. The ActiveJob test_helper.rbis supposed to be used with minitest not with rspec. So you have to rebuild it's functionalitity. You can just call

但是,如果没有什么不能阻止您进行完整的集成测试。ActiveJob test_helper.rb应该与 minitest 一起使用,而不是与 rspec 一起使用。所以你必须重建它的功能。你可以打电话

expect(ActiveJob::Base.queue_adapter.enqueued_jobs).to eq 1

without requiring anything

不需要任何东西

Update 1:As noticed within a comment. ActiveJob::Base.queue_adapter.enqueued_jobsworks only by setting it the queue_adapter into test mode.

更新 1:正如评论中所注意到的。 ActiveJob::Base.queue_adapter.enqueued_jobs只能通过将 queue_adapter 设置为测试模式来工作。

# either within config/environment/test.rb
config.active_job.queue_adapter = :test

# or within a test setup
ActiveJob::Base.queue_adapter = :test

回答by tirdadc

Rspec 3.4now has have_enqueued_jobcooked in, which makes this a lot easier to test:

Rspec 3.4现在已经加入了have_enqueued_job,这使得它更容易测试:

it "enqueues a YourJob" do
  expect {
    get :your_action, {}
  }.to have_enqueued_job(YourJob)
end

it has other niceties for have_enqueued_jobto allow you to check the argument(s) and the number of times it should be queued up.

它还有其他优点,have_enqueued_job可以让您检查参数和它应该排队的次数。

回答by ChuckJHardy

Testing Rails ActiveJob with RSpec

使用 RSpec 测试 Rails ActiveJob

class MyJob < ActiveJob::Base
  queue_as :urgent

  rescue_from(NoResultsError) do
    retry_job wait: 5.minutes, queue: :default
  end

  def perform(*args)
    MyService.call(*args)
  end
end

require 'rails_helper'

RSpec.describe MyJob, type: :job do
  include ActiveJob::TestHelper

  subject(:job) { described_class.perform_later(123) }

  it 'queues the job' do
    expect { job }
      .to change(ActiveJob::Base.queue_adapter.enqueued_jobs, :size).by(1)
  end

  it 'is in urgent queue' do
    expect(MyJob.new.queue_name).to eq('urgent')
  end

  it 'executes perform' do
    expect(MyService).to receive(:call).with(123)
    perform_enqueued_jobs { job }
  end

  it 'handles no results error' do
    allow(MyService).to receive(:call).and_raise(NoResultsError)

    perform_enqueued_jobs do
      expect_any_instance_of(MyJob)
        .to receive(:retry_job).with(wait: 10.minutes, queue: :default)

      job
    end
  end

  after do
    clear_enqueued_jobs
    clear_performed_jobs
  end
end

回答by KARASZI István

There is a new rspec extensionwhich makes your life easier.

有一个新的rspec 扩展,让你的生活更轻松。

require 'rails_helper'

RSpec.describe MyController do
  let(:user) { FactoryGirl.create(:user) }
  let(:params) { { user_id: user.id } }
  subject(:make_request) { described_class.make_request(params) }

  it { expect { make_request }.to enqueue_a(RequestMaker).with(global_id(user)) }
end

回答by Archernar

I had some problems, maybe because I didn't include ActiveJob::TestHelper, but this worked for me...

我遇到了一些问题,也许是因为我没有包含 ActiveJob::TestHelper,但这对我有用...

Firstly ensure, that you have the queue adapter set to :testas above answers show.

首先确保您将队列适配器设置:test为如上答案所示。

For some reason clear_enqueued_jobsjobs in the afterblock didn't work for me, but the sourceshows we can do the following: enqueued_jobs.clear

出于某种原因clear_enqueued_jobsafter块中的工作对我不起作用,但来源显示我们可以执行以下操作:enqueued_jobs.clear

require 'rails_helper'
include RSpec::Rails::Matchers

RSpec.describe "my_rake_task", type: :rake do

  after do
    ActiveJob::Base.queue_adapter.enqueued_jobs.clear
  end  


  context "when #all task is run" do
    it "enqueues jobs which have been enabled" do
      enabled_count = get_enabled_count
      subject.execute
      expect(ActiveJob::Base.queue_adapter.enqueued_jobs.size).to eq(enabled_count)
    end

    it "doesn't enqueues jobs which have been disabled" do
      enabled_count = get_enabled_count
      subject.execute
      expect(ActiveJob::Base.queue_adapter.enqueued_jobs.size).to eq(enabled_count)
    end
  end

end