Enabling/disabling observers for testing 6

Posted by ryan Thu, 10 Apr 2008 02:53:50 GMT

If you use ActiveRecord observers in your application and are concerned about the isolation of your model unit tests, you probably want some way to disable/enable observers. Unfortunately, Rails doesn't provide an easy way to do this. So, here's some code I threw together a while ago to do just that.

module ObserverTestHelperMethods
  def observer_instances
    ActiveRecord::Base.observers.collect do |observer|
      observer_klass = \
        if observer.respond_to?(:to_sym)
          observer.to_s.camelize.constantize
        elsif observer.respond_to?(:instance)
          observer
        end
      observer_klass.instance
    end
  end

  def observed_classes(observer=nil)
    observed = Set.new
    (observer.nil? ? observer_instances : [observer]).each do |observer|
      observed += (observer.send(:observed_classes) + observer.send(:observed_subclasses))
    end
    observed
  end

  def observed_classes_and_their_observers
    observers_by_observed_class = {}
    observer_instances.each do |observer|
      observed_classes(observer).each do |observed_class|
        observers_by_observed_class[observed_class] ||= Set.new
        observers_by_observed_class[observed_class] << observer
      end
    end
    observers_by_observed_class
  end

  def disable_observers(options={})
    except = options[:except]
    observed_classes_and_their_observers.each do |observed_class, observers|
      observers.each do |observer|
        unless observer.class == except
          observed_class.delete_observer(observer)
        end
      end
    end
  end

  def enable_observers(options={})
    except = options[:except]
    observer_instances.each do |observer|
      unless observer.class == except
        observed_classes(observer).each do |observed_class|
          observer.send :add_observer!, observed_class
        end
      end
    end
  end
end

Include this in a Test::Unit::TestCase or 'include' in your RSpec configuration, whatever rocks your boat. Here's a stupid example:

class SomethingCoolTest < Test::Unit::TestCase
  include ObserverTestHelperMethods

  def setup
    disable_observers
  end

  def teardown
    enable_observers
  end

  def test_without_observers
    # ...
  end

end

When you go to test the behavior of the observer itself, simply disable/enable like the following to disable/enable all observers except the one you're testing:

class DispassionateObserverTest < Test::Unit::TestCase
  include ObserverTestHelperMethods

  def setup
    disable_observers :except => DispassionateObserver
  end

  def teardown
    enable_observers :except => DispassionateObserver
  end

  def test_without_observers_except_dispassionate_observer
    # ...
  end

end
  1. Luke Redpath about {{count}} hours later:

    I've done some testing around observers recently and we came up with a simple way of preventing observers from interfering with our tests - it's not as flexible as your solution but I'm not sure it needs to be that flexible.

    Given a model Foo, and an observer FooObserver, in our Foo tests, in the setup, we would stub the Foo#notify method (we are using mocha):

    class FooTest < Test::Unit::TestCase
      def setup
        @foo = Foo.new
        @foo.stubs(:notify) # no observers get called
      end
    end
    

    We would then test our Observers separately:

    class FooObserverTest < Test::Unit::TestCase
      def setup
        @observer = FooObserver.instance
      end
    end
    

    This allows us to test our objects and their observers in isolation; in general you can rely on Rails to do the right thing and make sure your observers get called in the right place although you could also write some integration/functional tests to confirm this.

  2. women louboutin high shoes over {{count}} years later:

    Crystal shoes fairy tale Cinderella has made a perfect love story.christian louboutin slingback Orsay As a result,every woman dreams of being Cinderella wonderdful.In the real world,it's the designer who created a sophisticated high-heeled shoes many of their gifts and light hands,and countless women and to help achieve their dreams.High-profile christian louboutin is one of the outstanding one them.Louboutin boots Many women are crazy,his shoes.christian louboutin Jane's independence,he has expanded his personal charm shoe designer's reputation.

  3. LED Strip about {{count}} years later:

    http://www.lighteveryday.com Welcome to LightEveryDay.com. Our company offer led lights,led strip, led ribbon, led car light, led power supply, led

    controller.High quality LED Strip with low price.

  4. assessments over {{count}} years later:

    This allows us to analyze our things and their experts in isolation; in common you can depend on Tracks to do the right factor and create sure your experts get known as in the right position although you could also create some integration/functional assessments to validate this dissertation-writing-help.org .

  5. http://www.tigersasicsausbuy.com/ about {{count}} years later:
  6. Asics Onitsuka Tiger about {{count}} years later: