Comment testeriez-vous les observateurs avec rSpec dans une application Ruby on Rails ?
-
09-06-2019 - |
Question
Supposons que vous ayez un ActiveRecord :: Observer dans l'une de vos applications Ruby on Rails - comment tester cet observateur avec rSpec ?
La solution
Vous êtes sur la bonne voie, mais j'ai rencontré un certain nombre d'erreurs de message inattendues et frustrantes lors de l'utilisation de rSpec, d'observateurs et d'objets fictifs.Lorsque je teste les spécifications de mon modèle, je ne veux pas avoir à gérer le comportement des observateurs dans mes attentes de message.
Dans votre exemple, il n'existe pas de très bon moyen de spécifier "set_status" sur le modèle sans savoir ce que l'observateur va y faire.
C'est pourquoi j'aime utiliser le Plugin "Pas de voyeurs". Compte tenu de votre code ci-dessus et en utilisant le plugin No Peeping Toms, je spécifierais le modèle comme ceci :
describe Person do
it "should set status correctly" do
@p = Person.new(:status => "foo")
@p.set_status("bar")
@p.save
@p.status.should eql("bar")
end
end
Vous pouvez spécifier le code de votre modèle sans avoir à craindre qu'un observateur vienne écraser votre valeur.Vous le spécifieriez séparément dans person_observer_spec comme ceci :
describe PersonObserver do
it "should clobber the status field" do
@p = mock_model(Person, :status => "foo")
@obs = PersonObserver.instance
@p.should_receive(:set_status).with("aha!")
@obs.after_save
end
end
Si vous voulez VRAIMENT VRAIMENT tester la classe couplée Model et Observer, vous pouvez le faire comme ceci :
describe Person do
it "should register a status change with the person observer turned on" do
Person.with_observers(:person_observer) do
lambda { @p = Person.new; @p.save }.should change(@p, :status).to("aha!)
end
end
end
99 % du temps, je préfère tester les spécifications avec les observateurs désactivés.C'est juste plus facile ainsi.
Autres conseils
Clause de non-responsabilité:Je n'ai jamais fait cela sur un site de production, mais il semble qu'un moyen raisonnable serait d'utiliser des objets fictifs, should_receive
et amis, et invoquez des méthodes directement sur l'observateur
Étant donné le modèle et l'observateur suivants :
class Person < ActiveRecord::Base
def set_status( new_status )
# do whatever
end
end
class PersonObserver < ActiveRecord::Observer
def after_save(person)
person.set_status("aha!")
end
end
J'écrirais une spécification comme celle-ci (je l'ai exécutée et elle réussit)
describe PersonObserver do
before :each do
@person = stub_model(Person)
@observer = PersonObserver.instance
end
it "should invoke after_save on the observed object" do
@person.should_receive(:set_status).with("aha!")
@observer.after_save(@person)
end
end
no_peeping_toms est désormais un joyau et peut être trouvé ici : https://github.com/patmaddox/no-peeping-toms
Si vous souhaitez tester que l'observateur observe le bon modèle et reçoit la notification comme prévu, voici un exemple utilisant RR.
votre_modèle.rb :
class YourModel < ActiveRecord::Base
...
end
votre_modèle_observer.rb :
class YourModelObserver < ActiveRecord::Observer
def after_create
...
end
def custom_notification
...
end
end
votre_modèle_observer_spec.rb :
before do
@observer = YourModelObserver.instance
@model = YourModel.new
end
it "acts on the after_create notification"
mock(@observer).after_create(@model)
@model.save!
end
it "acts on the custom notification"
mock(@observer).custom_notification(@model)
@model.send(:notify, :custom_notification)
end