tag:kinderman.net,2005:/tag/observerskinderman.net : Tag observers, everything about observerscode code code2008-04-09T19:53:51-07:00Typotag:kinderman.net,2005:Article/1082008-04-09T19:53:51-07:002008-04-09T19:53:51-07:00ryanEnabling/disabling observers for testing<p>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.</p>
<pre><code>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
</code></pre>
<p>Include this in a Test::Unit::TestCase or 'include' in your RSpec configuration, whatever rocks your boat. Here's a stupid example:</p>
<pre><code>class SomethingCoolTest < Test::Unit::TestCase
include ObserverTestHelperMethods
def setup
disable_observers
end
def teardown
enable_observers
end
def test_without_observers
# ...
end
end
</code></pre>
<p>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:</p>
<pre><code>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
</code></pre>