2016-10-24 1 views
2

J'ai un objet qui enregistre un modèle et exécute un travail d'arrière-plan.Vérifier qu'une séquence de messages est envoyée à différents objets/classes

Class UseCase 
    ... 
    def self.perform 
    @account.save 
    BackgroundJob.perform_later(@account.id) 
    end 
end 

Dans mon spec je voudrais tester séparément que les deux messages sont envoyés.

J'ai commencé avec quelque chose comme

it 'saves the account' do 
    expect_any_instance_of(Account).to receive(:save) 
    UseCase.perform(account) 
end 

Et cela a bien fonctionné quand je gardais juste le compte dans le perform. Mais quand j'ai ajouté le travail d'arrière-plan la spécification ne passe plus depuis maintenant Couldn't find Account without an ID.

Comment puis-je vérifier (en RSped 3.5) séparément que les deux messages sont envoyés?

MISE À JOUR

it 'runs the job' do 
expect(BackgroundJob).to receive(:perform_later).with(instance_of(Fixnum)) 
UseCase.perform(account) 
end 

passe je suppose que le compte est correctement enregistré.

Cependant, lorsque je tente d'inspecter @account

def self.perform 
@account.save 
byebug 
BackgroundJob.perform_later(@account.id) 
end 

Dans 'sauve le compte', je reçois

(byebug) @account 
#<Account id: nil, full_name: "john doe" ...> 

In 'exécute le travail', je reçois

(byebug) @account 
#<Account id: 1, full_name: "john doe" ...> 

L'attente fait @account un test double donc dans la première spécification le travail ne peut pas obtenir l'ID.

Merci

+0

Avez-vous une spécification qui vérifie que '@ account.save' renvoie réellement' true'? Je suppose que '@account.save' renvoie 'false', le compte est invalide, n'a pas été sauvegardé et n'a donc pas d'identifiant. – spickermann

+0

Je crois que @spickermann est correct. J'ai ajouté une réponse pour expliquer la différence entre 'save!' Et 'save'. Espérons que cela vous aide –

Répondre

0

L'erreur Couldn't find Account without an ID est en fait assez utile compte tenu du code que vous avez dans votre méthode perform.

Le problème est mentionné dans les commentaires mais je vais développer un peu plus loin.

Vous utilisez @account.save (je suppose @account est un objet ActiveRecord) qui, par définition, sera de retour true/false lors de son exécution (see documentation)

Ce que vous voulez sans doute est d'utiliser à la place save! car il soulèvera une ActiveRecord::RecordInvalid erreur et arrêter l'exécution plutôt que de déclencher l'erreur que vous avez noté plus tôt. (Lancer un binding.pry dans la méthode et notez ce que @account est lorsque l'on tente d'appeler .id)

Lorsque vous passez à save! vous pouvez ajouter un test pour un cas où la sauvegarde peut échouer (manque attribut, etc.). Peut ressembler à quelque chose comme ça

it 'should raise error when trying to save invalid record' do 
    # do something to invalidate @account 
    @account.username = nil 
    expect { UseCase.perform(@account) }.to raise_error(ActiveRecord::RecordInvalid) 
    #confirm that no messages were sent 
end 

Espérons que ça vous aide! GL et laissez-moi savoir si vous avez des questions/besoin de plus d'aide avec rspec

+0

Merci pour la réponse. En fait, je ne comprends pas si vous suggérez que mon compte n'est pas sauvegardé ou qu'il est sauvegardé mais «sauvegarder» ne renvoie pas ce que je souhaite. – macsig

+0

s'il vous plaît lire la documentation que j'ai liée. Si 'save' renvoie false, votre enregistrement n'est pas enregistré dans la base de données (d'où l'absence d'identifiant) –