Как проверить, что очереди в ActiveJob используем RSpec
Я работаю над методом reset_password в приложении Rails API. Когда эта конечная точка попадает, ActiveJob ставится в очередь, которая будет запускать запрос Mandrill (наш транзакционный почтовый клиент). В настоящее время я пытаюсь написать тесты, чтобы убедиться, что ActiveJob правильно поставлен в очередь, когда конечная точка контроллера поражена.
def reset_password
@user = User.find_by(email: params[:user][:email])
@user.send_reset_password_instructions
end
send_reset_password_instructions создает некоторые url-адреса и т. д. Перед созданием ActiveJob, код которого приведен ниже:
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 момент, когда мы не используем адаптеры для ActiveJob, поэтому я просто хочу проверить с Rspec, что ActiveJob находится в очереди.
В настоящее время мой тест выглядит примерно так (я использую 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
все работает в реальности, мне просто нужно создавать тесты!
Я использую ruby 2.1.2 и rails 4.1.6.
Я не вижу никакой документации или помощи в интернете о том, как протестировать это, чтобы любая помощь была очень признателен!
6 ответов
принятый ответ больше не работает для меня, поэтому я попробовал предложение Майкла х. В комментариях, которое работает.
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
вам действительно не нужно тестировать функциональность ActiveJob. Просто проверьте, что ваш код вызывает его правильно, потушив его
expect(MyJob).to receive(:perform_later).once
post :reset_password, user: { email: user.email }
создатели ActiveJob использовали те же методы для своих модульных тестов. См.GridJob Testobject
они создают Testmock GridJob в своих тестах и переопределяют метод perform, так что он добавляет задания только в пользовательский массив, они называют JobBuffer. В конце они проверяют, имеет ли буфер работа в очереди
однако, если ничто не может остановить вас от выполнения полного интеграционного теста. В ActiveJob test_helper.rb предполагается использовать с minitest, а не с rspec. Поэтому вы должны восстановить его functionalitity. Вы можете просто позвонить
expect(ActiveJob::Base.queue_adapter.enqueued_jobs).to eq 1
ничего не требуя
обновление 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
Rspec 3.4 теперь have_enqueued_job приготовленный в, что делает это намного проще проверить:
it "enqueues a YourJob" do
expect {
get :your_action, {}
}.to have_enqueued_job(YourJob)
end
Он имеет другие тонкости для have_enqueued_job
чтобы вы могли проверить аргумент(Ы) и количество раз, когда он должен быть поставлен в очередь.
есть новый расширение 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
тестирование Rails ActiveJob с RSpec
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
у меня были некоторые проблемы, может быть, потому, что я не включил ActiveJob::TestHelper, но это сработало для меня...
во-первых, убедитесь, что у вас есть адаптер очереди :test
как выше ответы показывают.
почему-то clear_enqueued_jobs
работа в after
блок не работал для меня, но источник показывает, что мы можем сделать следующее: 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