Supposons que vous ayez un ActiveRecord :: Observer dans une de vos applications Ruby on Rails - comment testez-vous cet observateur avec rSpec?Comment testeriez-vous les observateurs avec rSpec dans une application Ruby on Rails?
Répondre
Vous êtes à droite suivi, mais j'ai rencontré un certain nombre d'erreurs de message inattendues frustrantes lors de l'utilisation rSpec, les observateurs et les objets fictifs. Quand je suis en train de tester mon modèle, je ne veux pas avoir à gérer le comportement d'observateur dans mes attentes de message.
Dans votre exemple, il n'y a pas vraiment de bonne façon de spécifier "set_status" sur le modèle sans savoir ce que l'observateur va lui faire.
Par conséquent, je tiens à utiliser le "No Peeping Toms" plugin. Compte tenu de votre code ci-dessus et en utilisant le No Peeping plug-in Toms, je spec le modèle comme celui-ci:
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 code de modèle sans avoir à se soucier que il y a un observateur là-bas qui va entrer et battre votre valeur. Vous souhaitez que spec séparément dans les person_observer_spec comme celui-ci:
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 le modèle couplé et la classe d'observation, 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% des le temps, je préfèrerais spec tester avec les observateurs éteints. C'est juste plus facile de cette façon.
Disclaimer: Je ne l'ai jamais réellement fait cela sur un site de production, mais il semble que d'une manière raisonnable serait d'utiliser des objets fantaisie, should_receive
et amis, et appeler des méthodes sur l'observateur directement
Compte tenu de ce qui suit modèle et 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 celui-ci (je l'ai couru, et il 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
Nous avons suivi cette approche et il fonctionne à merveille –
no_peeping_toms est maintenant un petit bijou et se trouve ici: https://github.com/patmaddox/no-peeping-toms
À partir de Rails 3.1 il existe une méthode de désactivation pour les observateurs. –
+1 no_peeping_toms –
Si vous voulez vérifier que l'observateur observe le bon modèle et reçoit la notification comme prévu, voici un exemple en utilisant 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
Si vous vouloir tester les observateurs puis un modèle que j'utilise est 'describe PersonOb serveur { around (: each) {| spec | Person.with_observers (: person_observer) {spec.run}}} 'Ceci permet à l'observateur de tous les tests dans le bloc de description de PersonObserver. – roo
Cette réponse est formulée comme une réponse, mais ce n'est pas clair à quoi. Il ne répond certainement pas directement à la question ... –