Je travaille sur une méthode reset_password dans une application API Rails. Lorsque ce point de terminaison est atteint, un ActiveJob est mis en file d'attente qui enverra une demande à Mandrill (notre client de messagerie transactionnel). Je '' m essaie actuellement d'écrire les tests pour s'assurer que l'ActiveJob est correctement mis en file d'attente lorsque le point de terminaison du contrôleur est atteint.
def reset_password
@user = User.find_by(email: params[:user][:email])
@user.send_reset_password_instructions
end
Le send_reset_password_instructions crée quelques URL, etc. avant de créer l'ActiveJob dont le code est ci-dessous:
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
Pour le moment, nous n'utilisons aucun adaptateur pour l'ActiveJob, donc je veux juste vérifier avec Rspec que l'ActiveJob est mis en file d'attente.
Actuellement, mon test ressemble à ceci (j'utilise Factory Girl pour créer l'utilisateur):
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
Tout fonctionne en réalité, j'ai juste besoin de créer les tests!
J'utilise Ruby 2.1.2 et Rails 4.1.6.
Je ne vois aucune documentation ni aucune aide sur le Web sur la façon de tester cela, donc toute aide serait grandement appréciée!
La réponse acceptée ne fonctionne plus pour moi, j'ai donc essayé la suggestion de Michael H. dans les commentaires, qui fonctionne.
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
Vous n'avez vraiment pas besoin de tester la fonctionnalité ActiveJob. Testez simplement que votre code l'appelle correctement en le supprimant
expect(MyJob).to receive(:perform_later).once
post :reset_password, user: { email: user.email }
Les créateurs de l'ActiveJob ont utilisé les mêmes techniques pour leurs tests unitaires. Voir GridJob Testobject
Ils créent un testmock GridJob dans leurs tests et remplacent la méthode perform, de sorte qu'il n'ajoute que des travaux à un tableau personnalisé, ils appellent JobBuffer . À la fin, ils testent si le tampon a des tâches en file d'attente
Cependant si rien ne peut vous empêcher de faire un test d'intégration complet. ActiveJob test_helper.rb est censé être utilisé avec minitest et non avec rspec. Vous devez donc reconstruire sa fonctionnalité. Vous pouvez simplement appeler
expect(ActiveJob::Base.queue_adapter.enqueued_jobs).to eq 1
sans rien exiger
Mise à jour 1: Comme remarqué dans un commentaire. ActiveJob::Base.queue_adapter.enqueued_jobs
fonctionne uniquement en le plaçant le queue_adapter en mode test.
# 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 a maintenant have_enqueued_job cuit, ce qui rend cela beaucoup plus facile à tester:
it "enqueues a YourJob" do
expect {
get :your_action, {}
}.to have_enqueued_job(YourJob)
end
il a d'autres subtilités pour have_enqueued_job
pour vous permettre de vérifier les arguments et le nombre de fois où ils doivent être mis en file d'attente.
Test Rails ActiveJob avec 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
Il y a une nouvelle extension rspec qui vous facilite la vie.
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
J'ai eu quelques problèmes, peut-être parce que je n'ai pas inclus ActiveJob :: TestHelper, mais cela a fonctionné pour moi ...
Assurez-vous d'abord que l'adaptateur de file d'attente est défini sur :test
comme le montrent les réponses ci-dessus.
Pour certaines raisons clear_enqueued_jobs
les travaux dans le bloc after
n'ont pas fonctionné pour moi, mais le source montre que nous pouvons faire ce qui suit: 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