2008-08-28 28 views

回答

35

你在正確的跟蹤,但在使用rSpec,觀察者和模擬對象時,我遇到了一些令人沮喪的意外消息錯誤。當我對規範進行規範測試時,我不希望在消息期望中處理觀察者行爲。

在你的例子中,沒有一個真正好的方法來規範模型中的「set_status」,而不知道觀察者會對它做什麼。

因此,我喜歡用上面給出你的代碼,並使用無偷窺插件"No Peeping Toms" plugin.,我會符合規範的模式是這樣的:

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 

您可以規範模型代碼,而不必擔心那裏有一個觀察員將會進來並打破你的價值。你會在這樣的person_observer_spec是單獨規格:

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 

如果你真的真的要測試的耦合模型和觀察類,你可以做這樣的:的

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%那個時候,我寧願在關閉觀察者的情況下進行spec測試。這樣就更簡單了。

+0

如果您想要測試觀察者,那麼我使用的模式是 `描述PersonOb服務器{(各個){| spec |。} Person.with_observers(:person_observer){spec.run}}}`這使得觀察者可以在PersonObserver describe塊中進行所有測試。 – roo 2013-01-21 04:02:58

+0

這個答案似乎是一個答覆,但它不清楚什麼。這當然不是直接回答這個問題...... – 2014-05-01 16:45:21

15

聲明:我從來沒有真正做過這在生產現場,但它看起來像一個合理的方式是使用模擬對象,should_receive和朋友,並調用觀察者方法直接

鑑於以下模型和觀察員:

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 

我會寫這樣的規格(我跑了它,並把它傳遞)

​​
+0

我們一直在關注這個方法,它奇妙的作品 – 2010-08-19 15:41:50

2

如果你想測試觀察者所觀察的正確型號和接收預期的通知,下面是一個使用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 
相關問題