假设你的一个 Ruby on Rails 应用程序中有一个 ActiveRecord::Observer - 你如何使用 rSpec 测试这个观察者?
您在正确的Rails上,但是在使用 rSpec、观察者和模拟对象时,我遇到了许多令人沮丧的意外消息错误。当我规范测试我的模型时,我不想在我的消息期望中处理观察者的行为。
在您的示例中,如果不知道观察者将对它做什么,就没有一种非常好的方法来指定模型上的"set_status"。
因此,我喜欢使用"No Peeping Toms"插件。鉴于您上面的代码并使用 No Peeping Toms 插件,我会像这样指定模型:
1 2 3 4 5 6 7 8
| 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 中单独指定:
1 2 3 4 5 6 7 8
| 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 类,你可以这样做:
1 2 3 4 5 6 7
| 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% 的时间,我宁愿在关闭观察者的情况下进行规范测试。这样更容易。
免责声明:我实际上从未在生产站点上这样做过,但看起来合理的方法是使用模拟对象、should_receive 和朋友,并直接在观察者上调用方法
给定以下模型和观察者:
1 2 3 4 5 6 7 8 9 10 11
| 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 |
我会写一个这样的规范(我运行了它,它通过了)
1 2 3 4 5 6 7 8 9 10 11
| 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 现在是一个ruby,可以在这里找到:https://github.com/patmaddox/no-peeping-toms
如果您想测试观察者观察到正确的模型并按预期接收通知,这里是使用 RR 的示例。
your_model.rb:
1 2 3
| class YourModel ActiveRecord::Base
...
end |
your_model_observer.rb:
1 2 3 4 5 6 7 8 9
| class YourModelObserver ActiveRecord::Observer
def after_create
...
end
def custom_notification
...
end
end |
your_model_observer_spec.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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 |