2010-07-01 13 views
3

Je suis toujours un travail sur l'apprentissage RSpec donc je suis désolé si complètement oublié quelque chose ...modèles d'essai avec des relations et callbacks dans Rails avec RSpec et Factory_Girl

J'écris un test pour une recette a beaucoup d'ingrédients. Les ingrédients sont réellement ajoutés en pourcentage (avec une colonne% totale sur la formulation), donc je veux m'assurer que la colonne totale est mise à jour après chaque sauvegarde.

Donc maintenant mon test RSpec pour le modèle recipe_ingredient a quelque chose comme ceci:

it "should update recipe total percent" do 
    @recipe = Factory.create(:basic_recipe) 

    @ingredient.attributes = @valid_attributes.except(:recipe_id) 
    @ingredient.recipe_id = @recipe.id 
    @ingredient.percentage = 20 
    @ingredient.save! 

    @recipe.total_percentage.should == 20 
end 

J'ai une méthode after_save qui appelle simplement une mise à jour rapide sur l'ingrédient réception juste sauvé. C'est très simple:

EDIT: Cette action update_percentage est dans le modèle de recette. La méthode que j'appelle après avoir sauvegardé un ingrédient regarde juste sa recette, puis appelle cette méthode.

def update_percentage  
    self.update_attribute(:recipe.total_percentage, self.ingredients.calculate(:sum, :percentage)) 
end 

Est-ce que je me trompe? Est-ce que je n'ai pas accès à l'objet parent lors de l'exécution des tests? J'ai essayé d'exécuter une méthode de base pour changer le nom de la recette parent après la sauvegarde, mais cela n'a pas fonctionné. Je suis sûr que c'est quelque chose dans la relation que j'ai oublié, mais toutes les relations sont configurées correctement.

Merci pour toute aide/conseil!

Répondre

2

update_attribute est de mettre à jour les attributs de l'objet courant. Cela signifie que vous devez appeler update_attribute sur l'objet dont vous souhaitez mettre à jour l'attribut. Dans ce cas, vous voulez mettre à jour la recette, pas l'ingrédient. Donc, vous devez appeler recipe.update_attribute(:total_percentage, ...).

En outre, les ingrédients appartiennent à des recettes, pas d'autres ingrédients. Donc, au lieu de self.ingredients.sum(:percentage), vous devriez vraiment appeler recipe.ingredients.sum(:percentage). De plus, vous devrez recharger @recipe avant de le tester total_percentage. Même s'il fait référence au même enregistrement de base de données que @ingredient.recipe, il ne pointe pas vers le même objet Ruby en mémoire, de sorte que les mises à jour de l'un n'apparaissent pas dans l'autre. Recharger @recipe pour récupérer les dernières valeurs de la base de données après avoir enregistré le @ingredient.

+0

Désolé pour la méthode de confusion update_percentage est dans le modèle Recipe. La méthode after_save pour l'ingrédient charge la recette (@recipe = Recipe.find (self.recipe_id)), puis appelle le update_percentage dessus (@ recipe.update_percentage) Comment recharger la recette dans le test? – sshefer

+0

Essayé "@ recipe.reload" dans le test et cela a fonctionné. Merci Ian, je n'avais pas réalisé que je devais faire ça! – sshefer

2

Soit dit en passant, vous pouvez construire votre ingrédient d'une manière plus claire, puisque vous utilisez déjà factory_girl:

@ingredient = Factory(:ingredient, :recipe => @recipe, :percentage => 20) 

Cela va construire et sauver un ingrédient.

+0

Je ne suis pas digne :). Mon code vous remercie. – sshefer

0

Hé, ou vous mettez un @ recipe.reload avant de vérifier le total_percentage sur la recette, ou utilisez expect.

it "should update recipe total percent" do 
    @recipe = Factory.create(:basic_recipe) 
    expect { 
    @ingredient.attributes = @valid_attributes.except(:recipe_id) 
    @ingredient.recipe_id = @recipe.id 
    @ingredient.percentage = 20 
    @ingredient.save! 
    }.to change(@recipe,:total_percentage).to(20) 
end 

Je vous recommande de jeter un coup d'œil sur cette présentation. De nombreux conseils sur les nouveautés et les trucs sympas sur rspec. http://www.slideshare.net/gsterndale/straight-up-rspec

Expect est un alias lambda {} doit et vous pouvez en lire davantage ici. Rspec.rubyforge.org/rspec/1.3.0/classes/Spec/Matchers.html#M000168

Questions connexes