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 ==)
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
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