<p>Suppose you have an ActiveRecord::Observer in one of your Ruby on Rails applications - how do you test this observer with rSpec?</p>

[{'answer_id': 33869, 'author': 'Orion Edwards', 'author_id': 234, 'author_profile': 'https://Stackoverflow.com/users/234', 'pm_score': 4, 'selected': False, 'text': '<p>Disclaimer: I\'ve never actually done this on a production site, but it looks like a reasonable way would be to use mock objects, <code>should_receive</code> and friends, and invoke methods on the observer directly</p>\n\n<p>Given the following model and observer:</p>\n\n<pre><code>class Person &lt; ActiveRecord::Base\n  def set_status( new_status )\n    # do whatever\n  end\nend\n\nclass PersonObserver &lt; ActiveRecord::Observer\n  def after_save(person)\n    person.set_status("aha!")\n  end\nend\n</code></pre>\n\n<p>I would write a spec like this (I ran it, and it passes)</p>\n\n<pre><code>describe PersonObserver do\n  before :each do\n    @person = stub_model(Person)\n    @observer = PersonObserver.instance\n  end\n\n  it "should invoke after_save on the observed object" do\n    @person.should_receive(:set_status).with("aha!")\n    @observer.after_save(@person)\n  end\nend\n</code></pre>\n'}, {'answer_id': 130114, 'author': 'Pete', 'author_id': 13472, 'author_profile': 'https://Stackoverflow.com/users/13472', 'pm_score': 6, 'selected': True, 'text': '<p>You are on the right track, but I have run into a number of frustrating unexpected message errors when using rSpec, observers, and mock objects. When I am spec testing my model, I don\'t want to have to handle observer behavior in my message expectations. </p>\n\n<p>In your example, there isn\'t a really good way to spec "set_status" on the model without knowledge of what the observer is going to do to it. </p>\n\n<p>Therefore, I like to use the <a href="http://patmaddox.com/2007/11/23/better-rails-testing-decoupling-observers/" rel="noreferrer">"No Peeping Toms" plugin.</a> Given your code above and using the No Peeping Toms plugin, I would spec the model like this: </p>\n\n<pre><code>describe Person do \n  it "should set status correctly" do \n    @p = Person.new(:status =&gt; "foo")\n    @p.set_status("bar")\n    @p.save\n    @p.status.should eql("bar")\n  end\nend\n</code></pre>\n\n<p>You can spec your model code without having to worry that there is an observer out there that is going to come in and clobber your value. You\'d spec that separately in the person_observer_spec like this: </p>\n\n<pre><code>describe PersonObserver do\n  it "should clobber the status field" do \n    @p = mock_model(Person, :status =&gt; "foo")\n    @obs = PersonObserver.instance\n    @p.should_receive(:set_status).with("aha!")\n    @obs.after_save\n  end\nend \n</code></pre>\n\n<p>If you REALLY REALLY want to test the coupled Model and Observer class, you can do it like this:</p>\n\n<pre><code>describe Person do \n  it "should register a status change with the person observer turned on" do\n    Person.with_observers(:person_observer) do\n      lambda { @p = Person.new; @p.save }.should change(@p, :status).to("aha!)\n    end\n  end\nend\n</code></pre>\n\n<p>99% of the time, I\'d rather spec test with the observers turned off. It\'s just easier that way. </p>\n'}, {'answer_id': 5555454, 'author': 'William Dix', 'author_id': 663243, 'author_profile': 'https://Stackoverflow.com/users/663243', 'pm_score': 2, 'selected': False, 'text': '<p>no_peeping_toms is now a gem and can be found here: <a href="https://github.com/patmaddox/no-peeping-toms" rel="nofollow">https://github.com/patmaddox/no-peeping-toms</a></p>\n'}, {'answer_id': 5930831, 'author': 'Sujoy Gupta', 'author_id': 634977, 'author_profile': 'https://Stackoverflow.com/users/634977', 'pm_score': 2, 'selected': False, 'text': '<p>If you want to test that the observer observes the correct model and receives the notification as expected, here is an example using RR.</p>\n\n<p>your_model.rb:</p>\n\n<pre><code>class YourModel &lt; ActiveRecord::Base\n    ...\nend\n</code></pre>\n\n<p>your_model_observer.rb:</p>\n\n<pre><code>class YourModelObserver &lt; ActiveRecord::Observer\n    def after_create\n        ...\n    end\n\n    def custom_notification\n        ...\n    end\nend\n</code></pre>\n\n<p>your_model_observer_spec.rb:</p>\n\n<pre><code>before do\n    @observer = YourModelObserver.instance\n    @model = YourModel.new\nend\n\nit "acts on the after_create notification"\n    mock(@observer).after_create(@model)\n    @model.save!\nend\n\nit "acts on the custom notification"\n    mock(@observer).custom_notification(@model)\n    @model.send(:notify, :custom_notification)\nend\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/33048', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2569/']