web-dev-qa-db-fra.com

Rspec teste delay_job

J'ai des processus complexes et à longue durée de travail différé dans mon application. J'utilise Rspec pour tester des méthodes et des classes individuelles utilisées dans les processus, mais je voudrais également effectuer de nombreux travaux d'arrière-plan de bout en bout, avec différentes données de test.

Je n'ai rien trouvé sur le wiki de delay_job à ce sujet, et cette SO question semble intéressante mais je n'ai pas vraiment compris ce qui se passe ici. Quelle est la meilleure façon de tester chaînes de temporisation avec rSpec?

Je peux facilement configurer les données de test avec une usine, puis appeler la classe qui démarre le traitement en arrière-plan. Je m'attends à ce que les tests prennent beaucoup de temps.

code d'arrière-plan modifié

class Singleplex
    def perform(batch_id,user)   
      batch = start_batch(batch_id,user)
        ... do lots of stuff ...
    end
    handle_asynchronously :perform, queue: :singleplex, :run_at => Proc.new { 1.second.from_now }

spec/factories/batches.rb

FactoryGirl.define do
  factory :batch do
    batch_type 'singleplex'
    name 'valid panel'
    status 'ready'
  end

  factory :batch_detail do
    chrom 7
    chrom_start 140435012
    chrom_end 140435012
    target_offset 150
    padding 4
    primer3_parameter_id 1
    snp_mask 't'
    status 'ready'
    batch
  end
end

Ensuite, lancez le test comme ceci

describe Batch do  
  it 'runs Singleplex for a valid panel' do
    batch = FactoryGirl.create(:batch)
    user = User.find(1)
    status =  Singleplex.new.perform(batch.id,user)
    expect(status.should == true)
  end
end

J'ai deux problèmes à résoudre:

1) Comment dire au test d'attendre la fin de l'appel de temporisation avant de valider les résultats?

2) Pour valider les résultats, je devrai vérifier les valeurs dans plusieurs tableaux. Quelle est la meilleure façon de procéder dans Rspec?

ÉDITER

Je devrais ajouter que j'obtiens un objet temporisé, donc bien sûr la vérification d'état échoue. Les travaux durent généralement au moins 10 minutes.

1) Batch runs Singleplex for a valid panel
     Failure/Error: expect(status.should == true)
       expected: true
            got: #<Delayed::Backend::ActiveRecord::Job id: nil, priority: 0, attempts: 0, handler: "--- !Ruby/object:Delayed::PerformableMethod\nobject:...", last_error: nil, run_at: nil, locked_at: nil, failed_at: nil, locked_by: nil, queue: nil, created_at: nil, updated_at: nil> (using ==)
25
ardochhigh

Il y a plusieurs façons de procéder. Tous nécessitent que vous exécutiez le travail dans votre code.

Méthode 1: un test qui met le travail en file d'attente, puis indique au DelayedJob::Worker pour le compléter.

describe Batch do  
  it 'runs Singleplex for a valid panel' do
    batch = FactoryGirl.create(:batch)
    user = User.find(1)
    Singleplex.new.perform(batch.id,user)
    expect(Delayed::Worker.new.work_off).to eq [1, 0] # Returns [successes, failures]
    # Add expectations which check multiple tables to make sure the work is done
  end
end

Méthode 2: un test qui exécute le travail en question avec la mise en file d'attente désactivée et vérifie les résultats souhaités. Vous pouvez retarder la mise en file d'attente en appelant Delayed::Worker.delay_jobs = false quelque part dans votre configuration de test ou dans un bloc before.

before(:each) do
  Delayed::Worker.delay_jobs = false
end
describe Batch do  
  it 'runs Singleplex for a valid panel' do
    batch = FactoryGirl.create(:batch)
    user = User.find(1)
    Singleplex.new.perform(batch.id,user)
    # expectations which check that the work is done
  end
end

Cette méthode est cependant connue pour provoquer des problèmes avec les rappels .

Méthode 3: Écrivez un observateur qui surveille les nouveaux travaux créés et les exécute. De cette façon, vous n'aurez pas à déclarer manuellement "work_off" dans vos tests. Artsy a un Gist pour cela .

C'est aussi une bonne idée d'avoir des tests ailleurs pour s'assurer que les travaux sont mis en file d'attente comme prévu

it "queues welcome when a user is created" do
  expect(Delayed::Job.count).to eq 0
  # Create user step
  expect(Delayed::Job.count).to eq 1 # You should really be looking for the count of a specific job.
end
37
fny

Si vous souhaitez exécuter un travail retardé autour d'un seul test ou d'un ensemble de tests, vous pouvez l'ajouter à votre spec_helper.rb

config.around(:each, :run_delayed_jobs) do |example|
  Delayed::Worker.delay_jobs = false

  example.run

  Delayed::Worker.delay_jobs = true
end

Et appelez-le avec:

it 'runs the job', :run_delayed_jobs do
  # delayed job magic
end
8
stevenspiel