Come testeresti gli osservatori con rSpec in un'applicazione Ruby on Rails?
-
09-06-2019 - |
Domanda
Supponiamo di avere un ActiveRecord::Observer in una delle tue applicazioni Ruby on Rails: come testare questo osservatore con rSpec?
Soluzione
Sei sulla strada giusta, ma mi sono imbattuto in una serie di frustranti errori di messaggio imprevisti durante l'utilizzo di rSpec, osservatori e oggetti fittizi.Quando sto testando le specifiche del mio modello, non voglio dover gestire il comportamento dell'osservatore nelle aspettative dei miei messaggi.
Nel tuo esempio, non esiste un modo davvero valido per specificare "set_status" sul modello senza sapere cosa gli farà l'osservatore.
Pertanto, mi piace usare il Plug-in "Nessun guardone". Dato il codice riportato sopra e utilizzando il plugin No Peeping Toms, specificherei il modello in questo modo:
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
Puoi specificare il codice del tuo modello senza doverti preoccupare che ci sia un osservatore là fuori che entrerà e ostacolerà il tuo valore.Lo specificheresti separatamente in person_observer_spec in questo modo:
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
Se vuoi VERAMENTE VERAMENTE testare la classe accoppiata Modello e Osservatore, puoi farlo in questo modo:
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
Il 99% delle volte preferisco eseguire il test delle specifiche con gli osservatori spenti.È semplicemente più facile così.
Altri suggerimenti
Disclaimer:In realtà non l'ho mai fatto in un sito di produzione, ma sembra che un modo ragionevole sarebbe usare oggetti finti, should_receive
e amici, e invocare metodi direttamente sull'osservatore
Dato il seguente modello e osservatore:
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
Vorrei scrivere una specifica come questa (l'ho eseguita e passa)
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 ora è un gioiello e può essere trovato qui: https://github.com/patmaddox/no-peeping-toms
Se si desidera verificare che l'osservatore osservi il modello corretto e riceva la notifica come previsto, ecco un esempio utilizzando RR.
tuo_modello.rb:
class YourModel < ActiveRecord::Base
...
end
tuo_modello_osservatore.rb:
class YourModelObserver < ActiveRecord::Observer
def after_create
...
end
def custom_notification
...
end
end
tuo_modello_osservatore_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