我们将如何在Ruby on Rails应用程序中使用rSpec测试观察者?
时间:2020-03-05 18:44:35 来源:igfitidea点击:
假设一个Ruby on Rails应用程序中有一个ActiveRecord :: Observer,如何使用rSpec测试此观察器?
解决方案
回答
免责声明:我实际上从未在生产站点上执行过此操作,但看起来合理的方法是使用模拟对象," 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
回答
工作方向正确,但是使用rSpec,观察者和模拟对象时,遇到了许多令人沮丧的意外消息错误。当我对模型进行规范测试时,我不想在期望的消息中处理观察者的行为。
在示例中,在不知道观察者将要做什么的情况下,没有一种真正好的方法在模型上指定" set_status"。
因此,我喜欢使用" No Peeping Toms"插件。给定我们上面的代码并使用No Peeping Toms插件,我将指定这样的模型:
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
如果我们确实要测试耦合的Model和Observer类,则可以这样做:
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%的时间,我宁愿关闭观察者进行规格测试。这样比较容易。