2008-08-28 9 views

Odpowiedz

35

Jesteś na prawo śledzić, ale natknąłem się na wiele frustrujących nieoczekiwanych błędów komunikatów podczas korzystania z funkcji rSpec, obserwatorów i obiektów symulowanych. Kiedy testuję swój model, nie chcę mieć do czynienia z zachowaniem obserwatora w moich oczekiwaniach dotyczących wiadomości.

W twoim przykładzie nie ma naprawdę dobrego sposobu na specyfikację "set_status" w modelu bez wiedzy o tym, co obserwator zrobi.

Dlatego chciałbym użyć "No Peeping Toms" plugin. Biorąc kod powyżej i za pomocą wtyczki nr Peeping Toms, chciałbym wg planu model takiego:

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 

Można wg planu kod modelu, nie martwiąc się, że jest tam obserwator, który wejdzie i obrzuci twoją wartość. Byłbyś wg planu, który oddzielnie w person_observer_spec jak ten:

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 

Jeśli naprawdę bardzo chcesz przetestować sprzężony model i klasę obserwatorem, można to zrobić tak:

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% z tym razem wolałbym przeprowadzić test z wyłączonymi obserwatorami. W ten sposób jest po prostu łatwiej.

+0

Jeśli chcę przetestować obserwatorów, a wzór, którego używam, to: 'opis PersonOb serwer { wokół (: każdy) {| spec | Person.with_observers (: person_observer) {spec.run}}} 'Pozwala to obserwatorowi na wszystkie testy w bloku opisującym PersonObserver. – roo

+0

Ta odpowiedź jest sformułowana jak odpowiedź, ale nie jest do końca jasne, co. Z pewnością nie odpowiada bezpośrednio na pytanie ... –

15

Zastrzeżenie: Nigdy rzeczywiście zrobić to na miejscu produkcji, ale wygląda na to rozsądny sposób byłoby użyć makiety obiektów, should_receive i przyjaciół, i wywoływać metody na obserwatora bezpośrednio

Biorąc pod uwagę następujące Model i obserwator:

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 

chciałbym napisać specyfikację takiego (Pobiegłem go i przechodzi)

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 
+0

Byliśmy po to podejście i działa cudownie –

2

Jeśli chcesz przetestować, że obserwator zauważa właściwy model i otrzymał zawiadomienie zgodnie z oczekiwaniami, to jest przykład za pomocą 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