"def rescue_action(e) raise e end" causing problems in integration tests / autotest

Functional tests all come with a handy line that gives more sensible
exception reporting, looking something like :

class FooController; def rescue_action(e) raise e end; end

This causes problems in autotest. AFAICT, autotest doesn't reload the
controllers when moving between functional tests and integration tests,
so controllers still have the rewritten rescue_action method in
integration.

Normally, this doesn't matter. When an exception is raised, you get an
HTTP status of 500, as expected, and you don't notice that
rescue_action is behaving differently.
However, the status 500 is being set by dispatcher.rb:42, and so there
are differences. In particular, ActiveRecord::RecordNotFound is
supposed to return a status of 404. In autotest's integration
testing, you might get 404, you might get 500, depending on whether or
not your functional tests got loaded first on that particular run.

Has anyone found a workaround for this? At the moment I'm having to
remove the "def rescue_action(e) raise e end" line from functional
tests, and it's making functional test debugging a bit painful...

Jon

Jon wrote the following on 10.01.2007 15:54 :

Functional tests all come with a handy line that gives more sensible
exception reporting, looking something like :

class FooController; def rescue_action(e) raise e end; end

This causes problems in autotest. AFAICT, autotest doesn't reload the
controllers when moving between functional tests and integration tests,
so controllers still have the rewritten rescue_action method in
integration.

Normally, this doesn't matter. When an exception is raised, you get an
HTTP status of 500, as expected, and you don't notice that
rescue_action is behaving differently.
However, the status 500 is being set by dispatcher.rb:42, and so there
are differences. In particular, ActiveRecord::RecordNotFound is
supposed to return a status of 404. In autotest's integration
testing, you might get 404, you might get 500, depending on whether or
not your functional tests got loaded first on that particular run.

Has anyone found a workaround for this? At the moment I'm having to
remove the "def rescue_action(e) raise e end" line from functional
tests, and it's making functional test debugging a bit painful...

I've no solution for you, but I've found another problem with
integration/functionnal tests that gets in the way with autotest. For
nearly all tests, I'm using a method for login a user in with this kind
of code :
old_controller = @controller
@controller = LoginController.new
post :login, <whatever_params_needed>
@controller = old_controller

There's a hack in Integration tests which prevents this (a cache returns
the same controller on each <whatever>Controller.new call) as soon as a
controller has been used in an integration test.

A solution :

# Make IntegrationTest classes revert their changes to
# ActionController::Base (which prevent functional tests from
# working properly)
module IntegrationTestPatch
    def self.included(base)
        base.class_eval do
            def run_with_cleanup(*args, &block)
                ActionController::Base.send(:include,
                                           
ActionController::Integration::ControllerCapture)
                run_without_cleanup(*args, &block)
                if
ActionController::Base.respond_to?(:clear_last_instantiation!)
                    ActionController::Base.send(:include,
RevertControllerCapture)
                end
            end
            alias_method :run_without_cleanup, :run
            alias_method :run, :run_with_cleanup
        end
    end
end

# Used to patch ActionController::Base
module RevertControllerCapture
    def self.included(base)
        base.class_eval do
            class << self
                alias_method :new, :new_without_capture
            end
        end
    end
end

I realize I could manipulate the session directly without using my
LoginController to the same effect and this problem would go away too,
but I'll have to duplicate the LoginController behaviour, which isn't DRY...

Lionel.