Предположим, что у вас есть ActiveRecord:: Observer в одном из приложений Ruby on Rails - как вы проверяете этого наблюдателя с помощью rSpec?
Как вы проверите наблюдателей с rSpec в приложении Ruby on Rails?
Ответ 1
Вы на правильном пути, но при использовании 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% случаев я бы предпочел тест с выключенными наблюдателями. Это просто проще.
Ответ 2
Отказ от ответственности: я никогда на самом деле не делал этого на производственном сайте, но разумным способом было бы использовать макетные объекты, 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
Ответ 3
no_peeping_toms теперь является драгоценным камнем, и его можно найти здесь: https://github.com/patmaddox/no-peeping-toms
Ответ 4
Если вы хотите проверить, что наблюдатель наблюдает за правильной моделью и получает уведомление, как ожидается, вот пример использования 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