(I made a similar post to the RoR mailing list and asked around on IRC but noone seems to have a handy answer (I also noticed that Typo doesn't do this sort of testing of their helpers either, so no help from my favorite source of silent advice).)
We've been having problems writing functional tests for helper methods that rely on ActionView methods. Here's a specific example.
In application_helper.rb I've got a method called 'party_link()':
def party_link(party)
link_to party.full_name, { :controller => 'contacts',
:action => 'view',
:category => party.category_name,
:id => party.id },
:class => 'a2'
end
It takes a Party object (person, organization...) and returns an HTML link to that party's contact page. Simple enough. And it appears to work well enough from the browser.
We want to test it, though, so we want to write a functional test that fires fixture Party data at it and ensure that it returns reasonable links, for some value of reasonable.
Since it's not in a particular controller's helper file (since it will be used by many controllers), we will create a trivial controller for use in testing. The problem we run into is that we can't seem to get the ActionView methods required to run party_link() visible while testing. Here's the functional test:
require File.dirname(__FILE__) + '/../test_helper'
require File.dirname(__FILE__) + '/../../app/controllers/application'
require File.dirname(__FILE__) + '/../../app/helpers/application_helper'
require 'action_view'
module LoginSystem
def unprotected?() true; end # drop login protection for this test controller
end
# dummy controller to drive helper tests
class HelperController < ActionController::Base
include ApplicationHelper
include ActionView
end
class HelperControllerTest < Test::Unit::TestCase
fixtures :party
include ApplicationHelper
def setup
@controller = HelperController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
# Test party_link function passing staff
def test_party_link_staff
link_data = @controller.party_link(party(:twburges))
end
end
Note that we're not even getting to an assert_* in test_party_link_staff(), because, well, we tried, and we just get an error, so we culled the assertions from the code I'm sending (so as not to confuse the issue).
1) Error:
test_party_link_staff(HelperControllerTest):
NoMethodError: undefined method `link_to' for #<HelperController:0xb69e32d0>
./test/functional/../../app/helpers/application_helper.rb:170:in `party_link'
./test/functional/bad_test.rb:30:in `test_party_link_staff'
Currently we're stubbing link_to() and checking that it gets called, which is The Wrong Way to fix the problem. We can 'include' ActionView, ActionView::Helpers, ActionView::Helpers::UrlHelper and get past link_to (and, I think url_for) but end up blowing on tag_options (IIRC). Seems like there must be a simpler and more straightforward way to do this, that I'm sure I missed in Rails 101.
What I'm looking for is a simple (perhaps undocumented?) way to include/require/extend something simple and allow my helpers to get access to the functionality they would normally have when running during the normal request-response cycle. Stubbing methods turns black-box testing into white-box testing and really defeats the purpose of "integration" testing by not allowing for true integration. Having to include/require every dependent module also creates white-box testing, artificial integration, and makes the tests very fragile (dependent upon the internals of Rails, which they shouldn't have to know about).