2010-12-07 3 views
31

Je me demandais comment tester un appel find_each dans rspec. Je suis habitué à tout simplement ce que je veux stubbing mes modèles pour revenir, donc je ne repose pas sur des données de test dans la db comme ceci:Comment puis-je trouver find_each pour les tests rspec dans les rails 3

MyClass.stub(:find).and_return(my_mock) 

Cependant, dans une autre classe que je fais ceci:

MyClass.find_each do |instance_of_my_class| 
    do_stuff_here_on(instance_of_my_class) 
end 

je trouve que si je fais ceci:

MyClass.stub(:find_each).and_return([one_mock, two_mock]) 

dans le test de spécification, la partie « faire des choses ici » n'est pas en cours d'exécution. Est-ce que quelqu'un sait comment souder un find_each pour les tests rspec?

Répondre

35

Vous pouvez utiliser and_yield pour faire rspec appeler le bloc passé à la maquette:

MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock) 
+0

Cela provoque l'erreur suivante: | my mocks in ici | bloquer avec l'arité de 1. Si je mets les mocks en tant que tableau, il n'y a pas de problème mais l'instance_of_my_class dans le bloc find_each est le tableau et non les éléments qui s'y trouvent. – Aaron

+4

Que diriez-vous de '.and_yield (one_mock) .and_yield (two_mock)'? – zetetic

+0

vous avez raison, zetetic - Je m'assurerai de tester mon conseil la prochaine fois :) J'ai édité ma réponse pour inclure votre correction. – Iain

2

Le point entier de la création de talons d'une méthode est que la méthode renvoie une valeur attendue et n'exécute pas son contenu. Si vous avez un tas de logique dans la méthode find_each, je recommanderais de le déplacer vers une méthode séparée et de tester cette logique séparément. Vous pouvez ensuite tester que votre méthode est appelée pendant l'exécution.

Voici un exemple de niveau assez élevé:

class Example1 
    def my_method 
    # some logic 
    end 
end 

class Example2 
    def my_other_method 
    Example1.find_each(&:my_method) 
    end 
end 

Rspec:

describe Example1 do 
    it "should return something" do 
    example = Example1.new 
    example.my_method.should == something 
    end 
end 

describe Example2 do 
    it "should call my_method on Example1" do 
    example1 = mock(:example1, :my_method => true) 
    example2 = Example2.new 

    example1.should_receive(:my_method) 
    example2.my_other_method 
    end 
end 
+0

que je fais en fait la logique dans une autre méthode que je teste. J'ai mis à jour le bloc find_each dans ma question pour refléter cela. J'essaie plus de tester qu'il effectue cela sur tous les mocks que je passe. – Aaron

1

Cette devrait le faire:

MyClass.stub(:find_each) {|block| 
    block.call 
    [one_mock, two_mock] 
} 

Si do_stuff_here_on n'est pas accessible globalement, par ex. une méthode d'instance sur some_object, vous aurez besoin d'instance_eval pour obtenir le champ droit du bloc:

MyClass.stub(:find_each) {|block| 
    some_object.instance_eval(&block) 
    [one_mock, two_mock] 
} 
Questions connexes