2016-12-29 1 views
0

J'essaie d'écrire un test Rspec défaillant. Le test réel est associé à un code beaucoup plus long, mais j'ai limité le problème à la méthode de classe qu'il est en train de tester.Rspec passe la méthode de classe mais échoue à la méthode de l'instance

est ici le test en Rspec:

context "For '.CASH.' as a stock" do 
    let!(:cash) { FactoryGirl.create(:stock, symbol: '.CASH.', name: 'cash', status: 'Available') } 

    describe "When update_stock runs on it" do 
    it "should still have an 'Available' status" do 
     # status should be 'Error' and test should fail 
     Stock.change_to_error 
     expect(cash.status).to eq('Available') 
    end 
    end 
end 

Ce teste une méthode de classe modèle Stock.rb:

def self.change_to_error 
    self.all.each do |stock| 
    stock.status = "Error" 
    stock.save 
    end 
end 

Pour une raison quelconque, cela passe. Cependant, si je l'ai changé d'utiliser une méthode d'instance, il échouera comme il se doit:

Si stock_spec.rb changé méthode d'instance:

context "For '.CASH.' as a stock" do 
let!(:cash) { FactoryGirl.create(:stock, symbol: '.CASH.', name: 'cash', status: 'Available') } 

    describe "When update_stock runs on it" do 
    it "should still have an 'Available' status" do 
     # status should be 'Error' and test should fail 
     cash.change_to_error 
     expect(cash.status).to eq('Available') 
    end 
    end 
end 

Et si la méthode de classe stock.rb transformé en une instance méthode:

def change_to_error 
    self.status = 'Error' 
    self.save 
end 

Cela passerait. Malheureusement, je dois utiliser une méthode de classe au lieu d'une méthode d'instance parce que je veux mettre à jour tous les stocks dans la base de données. Les méthodes "Change_to_error" sont juste là pour comprendre le problème. Est-ce que quelqu'un sait pourquoi il passe comme une méthode de classe quand il devrait échouer? Mais il échoue correctement lorsqu'il utilise une méthode d'instance? En réalité, ce qui se passe est que la méthode de classe ne change pas l'attribut status de 'cash', mais la méthode de l'instance le fait. Je ne sais pas pourquoi cela se passe.

Pour votre information, j'utilise rspec rails

+1

Pouvez-vous essayer de remplacer 'stock.save' par' stock.save! '? Si quelque chose ne va pas, cela déclenchera une exception. – 31piy

+0

J'ai essayé ça. N'a pas aidé. D'autres idées? – HoodieOnRails

+0

Essayez d'utiliser 'Stock.find_each {| stock | stock.update_column (: statut, 'Erreur')} '. – 31piy

Répondre

1

Le besoin de mettre « cash.reload » après « Stock.change_to_error » et avant la ligne attendre.

Lors de l'utilisation let! l'objet est créé avant le test. La mise à jour des données sous-jacentes en dehors de l'objet entraîne la pérennité de l'instance. Appeler le reload force ActiveRecord à l'actualiser à partir de la base de données.


Lorsque vous utilisez let, RSpec ne remet pas le bloc jusqu'à ce que la première fois que vous faites référence à l'attribut, dans ce cas, cash. Donc, dans votre premier exemple, vous exécutez change_to_error sur aucun enregistrement du tout, puis vérifiez l'état sur cash, un enregistrement qui est créé sur la ligne avec expect. Dans votre deuxième exemple, l'objet cash est créé, puis remplacé par une erreur. Je vous recommande de suivre votre journal pour le confirmer (tail -f log/test.log)

Si vous passez à let!, RSpec créera l'objet avant chaque exemple. Une autre alternative consiste à référencer cash dans votre exemple avant d'appeler change_to_error sur tous les enregistrements qui sont créés.

+0

Malheureusement, cela n'a pas fonctionné. Même si j'utilise une boucle before et utilise une variable d'instance de @cash au lieu de let (: cash), cela ne fonctionne pas. D'autres idées? – HoodieOnRails

+0

Bien que cela n'a pas résolu le problème, je me rends compte que votre observation est correcte dans le code que j'ai fourni ci-dessus. – HoodieOnRails

+1

Essayez de recharger 'cash' avant de vérifier le statut. Maintenant que vous utilisez let !, le modèle est créé, votre méthode de classe change les modèles sous-jacents, mais votre instance 'cash' peut toujours avoir la valeur mise en cache. Essayez 'cash.reload!', Puis vérifiez le statut. – mroach