Comment vérifier ce qui est mis en file D'attente dans ActiveJob en utilisant Rspec

je travaille sur une méthode reset_password dans une application de L'API Rails. Lorsque ce point final est atteint, une tâche active est mise en file d'attente qui déclenche une requête à Mandrill (notre client de messagerie transactionnel). Je suis en train d'essayer d'écrire les tests pour m'assurer que L'ActiveJob est mise en file d'attente correctement lorsque le terminal du contrôleur est touché.

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

les instructions send_reset_password_instructions créent des URLs 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

À le moment où nous n'utilisons pas d'adaptateur pour L'ActiveJob, donc je veux juste vérifier avec Rspec que L'ActiveJob est en file d'attente.

actuellement mon test ressemble à quelque chose comme 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 ou aide nulle part sur le web sur la façon de tester sur ce si toute aide serait grandement apprécié!

30
demandé sur mylescc 2014-10-09 13:30:04

6 réponses

la réponse acceptée ne fonctionne plus pour moi, donc j'ai 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
38
répondu Josh Smith 2014-12-24 15:34:24

vous n'avez vraiment pas besoin de tester la fonctionnalité ActiveJob. Il suffit de tester que votre code l'appelle correctement en le frappant hors

 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 une GridJob testmock dans leurs tests et supplantent la méthode perform, de sorte qu'elle ajoute seulement des jobs à un tableau personnalisé, ils appellent JobBuffer. À la fin, ils vérifient si le tampon a travaux en file d'attente

cependant si rien ne peut vous empêcher de faire un test d'intégration complet. The ActiveJob test_helper.rb est censé être utilisé avec minitest pas avec rspec. Donc vous devez reconstruire sa fonctionnalité. Vous pouvez les appeler

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

sans exiger rien

mise à Jour 1: Comme noté dans un commentaire. ActiveJob::Base.queue_adapter.enqueued_jobs ne fonctionne qu'en paramétrant le jeu_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
34
répondu dre-hh 2016-12-02 08:27:27

Rspec 3.4 a have_enqueued_job cuits, ce qui rend le test beaucoup plus facile:

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 l'argument(s) et le nombre de fois où il doit être mis en file d'attente.

13
répondu tirdadc 2015-11-16 13:52:39

Il y a un nouveau RSpec extension ce qui rend votre vie plus facile.

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
8
répondu KARASZI István 2015-03-17 14:22:06

les 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
8
répondu CharlesJHardy 2015-06-22 20:48:06

j'ai eu quelques problèmes, peut-être parce que je n'ai pas inclus ActiveJob::TestHelper, mais cela a fonctionné pour moi...

tout d'abord, assurez-vous que l'adaptateur de file d'attente est réglé sur :test comme le montrent les réponses ci-dessus.

Pour une raison quelconque clear_enqueued_jobs emplois after bloc ne fonctionne pas pour moi, mais source montre 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
0
répondu Archernar 2017-07-16 23:27:01