2011-06-15 3 views
21

Je me demandais simplement comment tester que les requêtes actionmailer sont réellement envoyées à la fonction delayed_job que dans rspec.Rails/Rspec: Test des emails de delayed_job

J'aurais supposé que c'était assez simple, mais ma file d'attente delayed_job ne semble pas s'incrémenter. Code ci-dessous:

Controller:

def create 
    @contact = Contact.new(params[:contact]) 
     if @contact.save 
     contactmailer = ContactMailer 
     contactmailer.delay.contact_message(@contact) 
     redirect_to(contacts_url) 
     else 
     render :action => "new" 
     end 

Spec:

it "queues mail when a contact is created" do 
    expectedcount = Delayed::Job.count + 1 
    Contact.stub(:new).with(mock_contact()) { mock_contact(:save => true) } 
    post :create, :contact => mock_contact 
    expectedcount.should eq(Delayed::Job.count) 
    end 

deux avant et après l'appel au contrôleur, le Retardé :: Job.count retourne 0. J'ai essayé de prendre le conditionnel du contrôleur, mais je ne peux toujours pas obtenir le nombre de travail retardé à incrémenter.

Toutes les suggestions - Cheer appréciées

Répondre

45

Vous pouvez également tester ce que les tâches vont faire en les exécutant ou en désactivant la mise en file d'attente.

Modifiez la configuration chaque fois que vous le souhaitez (c'est-à-dire dans un bloc before :each).

Delayed::Worker.delay_jobs = false 

ou effectuer vos travaux enregistrés

Delayed::Worker.new.work_off.should == [1, 0] 

J'utilise cette méthode avec bonheur pendant un certain temps. D'une part, en utilisant le nouveau support any_instance dans RSpec, vous pouvez tester vos effets de méthodes différées directement. Cependant, j'ai trouvé des tests qui utilisent work_off pour être lente.

Ce que je fais maintenant est généralement:

mock_delay = double('mock_delay').as_null_object 
MyClass.any_instance.stub(:delay).and_return(mock_delay) 
mock_delay.should_receive(:my_delayed_method) 

, j'ai une spécification distincte pour my_delayed_method. Ceci est beaucoup plus rapide, et probablement meilleure pratique de test unitaire - en particulier pour les contrôleurs. Bien que si vous faites des spécifications de demande ou d'autres spécifications au niveau de l'intégration, alors vous voulez probablement toujours utiliser work_off.

+0

J'aime cette façon. Notez que pour être complet, vous devez également tester (séparément) que les tâches retardées sont ajoutées à la table delayed_jobs. – brittohalloran

+1

C'est lisse - merci! – jpwynn

16

Je pense que votre objet fantaisie introduit en quelque sorte une erreur - il est difficile de dire exactement comment sans voir la définition de la méthode mock_contact.

Dans tous les cas, vous pouvez essayer quelque chose le long de ces lignes:

it "queues mail when a contact is created" do 
    Contact.stub(:new) { mock_model(Contact,:save => true) } 
    Delayed::Job.count.should == 0 
    post :create, {} 
    Delayed::Job.count.should == 1 
    end 

ou la version plus sexy (mise en garde: je finis toujours faire le chemin non-sexy):

it "queues mail when a contact is created" do 
    Contact.stub(:new) { mock_model(Contact,:save => true) } 
    expect { 
     post :create, {} 
    }.to change(Delayed::Job.count).by(1) 
    end 
8

Vous pouvez également suivre la convention (de Railscast 275) de

ActionMailer::Base.deliveries.last.to.should == user.email 

mais plutôt faire:

Delayed::Job.last.handler.should have_content(user.email) 
0

Ce fil est un peu vieux, mais voici mon aller à elle:

Créer une fonction expect_jobs

def expect_jobs n, time = nil 
    expect(Delayed::Job.count).to eq(n) 
    Timecop.travel(time) unless time.nil? 
    successes, failures = Delayed::Worker.new.work_off 
    expect(successes).to eq(n) 
    expect(failures).to eq(0) 
    expect(Delayed::Job.count).to eq(0) 
    Timecop.travel(Time.now) unless time.nil? 
end 

Puis appelez-le simplement avant de vérifier si le rappel a fait son travail. par exemple:

it "sends a chapter to the admin user" do 
    post :chapter_to_user, { chapter: @book.chapters.first} 
    expect_jobs(1) 
    SubscribeMailer.should have(1).delivery 
    SubscribeMailer.deliveries.should have(1).attachment 
end 

Cela semble fonctionner de mon côté, et me permet d'exécuter mes deux emplois retard et mes méthodes.

1

@zetetic Je pense que nous devons passer le bloc dans la méthode de changement ici.

Il shoulb comme ceci:

it "queues mail when a contact is created" do 
Contact.stub(:new) { mock_model(Contact,:save => true) } 
expect { 
    post :create, {} 
    }.to change { Delayed::Job.count }.by(1) 
end