Sunday, March 1, 2009

ActionView::TestCase errors Rails 2.1.2

I started to use the built in Rails test case extensions when we upgraded a few months ago, however every once and a while I run into something that causes me frustration to no end.

Our team wrote helper that would render a remote_function call as part of its contents:

require 'test_helper'
require 'action_view/test_case'

class ApplicationHelperTest < < method =""> :get, :controller => 'main', :action=> 'open_item', :id => 1)
end
end


Executing this test resulted in an odd error:

[root@new-host-2 qme]# ruby test/unit/application_helper_test.rb --name test_demonstrates_bug
Loaded suite test/unit/application_helper_test
Started
E
Finished in 0.516956 seconds.

1) Error:
test_demonstrates_bug(ApplicationHelperTest):
NoMethodError: undefined method `protect_against_forgery?' for #applicationhelpertest:0x2a97ff0d68
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_controller/test_process.rb:467:in `method_missing'
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_view/test_case.rb:55:in `method_missing'
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_view/helpers/prototype_helper.rb:1053:in `options_for_ajax'
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_view/helpers/prototype_helper.rb:443:in `remote_function'
test/unit/application_helper_test.rb:17:in `test_demonstrates_bug'
/usr/lib64/ruby/gems/1.8/gems/activesupport-2.1.2/lib/active_support/testing/setup_and_teardown.rb:67:in `__send__'
/usr/lib64/ruby/gems/1.8/gems/activesupport-2.1.2/lib/active_support/testing/setup_and_teardown.rb:67:in `run'

1 tests, 0 assertions, 0 failures, 1 errors

I do not know what the root of this was, but I figured that my test did not care about protecting against forgery so I defined the method:

def protect_against_forgery?
end

Then I ran the test again, which resulted in a new error:

1) Error:
test_demonstrates_bug(ApplicationHelperTest):
NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.url_for
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_view/helpers/url_helper.rb:71:in `send'
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_view/helpers/url_helper.rb:71:in `url_for'
/usr/lib64/ruby/gems/1.8/gems/actionpack-2.1.2/lib/action_view/helpers/prototype_helper.rb:461:in `remote_function'
test/unit/application_helper_test.rb:20:in `test_demonstrates_bug'
/usr/lib64/ruby/gems/1.8/gems/activesupport-2.1.2/lib/active_support/testing/setup_and_teardown.rb:67:in `__send__'
/usr/lib64/ruby/gems/1.8/gems/activesupport-2.1.2/lib/active_support/testing/setup_and_teardown.rb:67:in `run'

1 tests, 0 assertions, 0 failures, 1 errors

Reading the source code it turns out that UrlHelper is trying to invoke @controller.url_for... really? I thought that it was initialized in the TestCase setup method? Turns out that it only creates a controller in the event a method is missing on in the TestCase...
 
def method_missing(selector, *args)
controller = TestController.new
return controller.send!(selector, *args) if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
super
end

I then initialized the controller as an instance member in setup() and things worked just fine.
 
setup :setup_with_helper_class

def setup_with_helper_class
if helper_class && !self.class.ancestors.include?(helper_class)
self.class.send(:include, helper_class)
end
@controller = TestController.new
end

I am not sure if all of these crazy things I did were good or bad things, particularly if I have forever inhibited my ability to protect_from_forgery in my tests but I guess I can live with it until I can file a request for fix with the Rails team.
Hope this helps...

1 comment:

Anonymous said...
This comment has been removed by a blog administrator.