你将如何在Ruby on Rails应用程序中使用rSpectesting观察者?

假设你在一个Ruby on Rails应用程序中有一个ActiveRecord :: Observer – 你如何用rSpectesting这个观察者?

你在正确的轨道上,但是当使用rSpec,观察者和模拟对象时,我遇到了一些令人沮丧的意外消息错误。 当我正在testing我的模型时,我不希望在消息期望中处理观察者的行为。

在你的例子中,没有一个很好的方法来规范模型的“set_status”,而不知道观察者将要做什么。

所以我喜欢使用“不偷窥汤姆”插件。 考虑到上面的代码,并使用“不要偷窥汤姆斯”插件,我会这样的模型:

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 

如果你真的很想testing耦合模型和观察者类,你可以这样做:

 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%的时间,我宁愿规格testing与观察员closures。 这样就更简单了。

免责声明:我从来没有在生产网站上这样做过,但是看起来合理的方法是使用模拟对象, 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 

我会写这样的规范(我跑了,它通过)

 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现在是一个gem,可以在这里find: https : //github.com/patmaddox/no-peeping-toms

如果要testing观察者观察到正确的模型并按照预期接收通知,则使用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