Supposons que vous avez un ActiveRecord::Observateur dans l'une de vos Ruby on Rails applications - comment pouvez-vous tester cet observateur avec rSpec?
Réponses
Trop de publicités?Vous êtes sur la bonne voie, mais j'ai couru dans un certain nombre de frustrant inattendu message d'erreurs lors de l'utilisation de rSpec, les observateurs et les objets fantaisie. Quand je suis spec de tester mon modèle, je ne veux pas avoir à gérer observateur comportement dans mon message attentes.
Dans votre exemple, il n'y a pas une très bonne façon de spec "set_status" sur le modèle sans la connaissance de ce que l'observateur va faire pour elle.
Par conséquent, je tiens à utiliser le "Pas de Peeping Toms" plugin. Compte tenu de votre code ci-dessus et en utilisant le Pas de Peeping Toms plugin, je voudrais spec 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 spec votre modèle de code sans avoir à se soucier qu'il y a un observateur qui va venir dans et tabasser votre valeur. Vous auriez spec séparément dans le 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 VRAIMENT vous voulez VRAIMENT tester le Modèle couplé et Observateur de la classe, 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 spec test avec les observateurs éteint. C'est juste plus facile de cette façon.
Disclaimer: je ne l'ai jamais fait ça sur un site de production, mais il semble que, d'une manière raisonnable serait d'utiliser les objets fantaisie, should_receive
et les amis, et appeler des méthodes sur l'observateur directement
Étant donné le modèle suivant et de l'observateur:
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
Je voudrais écrire une spécification comme ceci (j'ai couru, et ça passe)
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 maintenant un bijou et peut être trouvé ici: https://github.com/patmaddox/no-peeping-toms
Si vous voulez tester que l'observateur observe le bon modèle et reçoit la notification comme prévu, voici un exemple d'utilisation de la RR.
your_model.rb:
class YourModel < ActiveRecord::Base
...
end
your_model_observer.rb:
class YourModelObserver < ActiveRecord::Observer
def after_create
...
end
def custom_notification
...
end
end
your_model_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