Test Your Helpers 29 comments

posted Friday, April 7, 2006 by topfunky

A glaring hole in the Test Driven Development aspirations of Rails is helper tests. And also view tests, which Eric Hodel is working on.

But back to helper tests….you can test them somewhat through your functional tests, but how can you test them individually?

Ryan Davis figured out a solution and I made it into a plugin!

Installation

Installation is simple:

./script/plugin discover
./script/plugin install helper_test

Usage

You can generate a test for the ApplicationHelper by running the generator:

./script/generate helper_test Application

Finally, require the helper_testcase in your test_helper. There is a commented line in the helper_testcase that you can copy and paste into your test_helper.

require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')

The files are generated inside the test/unit/helpers folder and will be run when unit tests are run.

It’s that simple!

The Tests

Within the application_helper_test.rb, you can call a helper method and check the output.

def test_show_page_nav
  output = show_page_nav
  assert_match %r{Cloneberry International}, output
end

I like to save the output of the method so I can do several tests against it without having to call it again. Others like to call it once and do an assert_equal against the entire string.

Caveats

Only a few helpers libraries are included in the parent class. If your helper calls a helper in Rails that is not listed, you can add it to the list.

# Add other helpers here if you need them
include ActionView::Helpers::ActiveRecordHelper

Conclusion

It feels better to be writing tests. Adding helper tests makes it that much more thorough. You know you’re doing the right thing.

So go write some tests and start feeling good!

29 comments

Leave a response

  • atmos

    dude, topfunky++

  • Geoff,

    Looks simple, I need to step up my test-game.

    FYI, I got the dreded “Application Error(Rails)” the first time my RSS client (Thunderbird) tried to read this post. 30 seconds later it was fine. Maybe worth a log check?

    Doh, now I got it again when submitting my comment from Thunderbird. We’ll see how submitting from firefox goes…no dice try 1. Try #2…Try #3…#4…

  • topfunky

    Yeah, I see a few 500 errors.

    I’ll check it out, and maybe upgrade to Rails 1.1.1 and the latest Typo to see if that helps.

  • You realize I’m totally stealing this for Test::Rails.

  • topfunky

    Yeah, we thought that might happen.

    Steal it!

  • Jamie

    Geoff, just thought I’d mention (having just tried this) that the files this plugin generates are named bad – if you rename helper_testcase.rb to helper_test_case.rb then Rails will automagically pick it up.

    Great stuff though :)

  • topfunky

    Fascinating. I didn’t know it would work that way, but I’ll try it.

  • topfunky

    Ok…you’re right, but you still need the “require” if you are going to run tests individually.

    I use TextMate’s built-in command-shift-R to run single tests, and it only works if helper_test_case.rb is explicitly required in test_helper.rb.

    I’ll change the plugin to use your suggestion anyway, and TextMate users can add the extra require, if needed.

  • Geoff,

    So speaking of plugins, what are the plugins you just couldn’t live without? I haven’t really found anything out there for rail plugins like say, firefox extensions. What do you recommmend? And is there a place that shows what others do?

  • weird, I can’t run the ‘script/plugin discover’ command.. when I run it, I get a list of URLs to confirm and finally:

    Add http://jthopple.textdriven.com/svn/public/rails/plugins/? [Y/n]
    (eval):3:in `each': undefined method `[]' for nil:NilClass (NoMethodError)
            from /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/plugin.rb:627:in `scrape'
            from /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/plugin.rb:601:in `parse!'
            from /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/plugin.rb:600:in `parse!'
            from /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/plugin.rb:411:in `parse!'
            from /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/plugin.rb:427:in `parse!'
            from /usr/lib/ruby/gems/1.8/gems/rails-1.0.0/lib/commands/plugin.rb:823
            from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:21:in `require'
            from /usr/lib/ruby/gems/1.8/gems/activesupport-1.2.5/lib/active_support/dependencies.rb:214:in `require'
            from script/plugin:3

    any help would be greatly appreciated, thanks! :)

  • Hmmm…I tried that url and I couldn’t reproduce the bug (it worked).

    What version of Ruby? Have you upgraded RubyGems lately?

  • Very unfortunately its totally breaks in Rails 1.2.2, thought it worked beautefully in 1.1.6. Also, was that included in Rails 1.2 directly, because its really a super awsome plugin

    ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:249:in `load_missing_constant': Expected /usr/local/RailsProjects/rails_apps/cmws/config/../app/helpers/cmws_helper.rb to define CMWSHelper (LoadError)
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:452:in `const_missing'
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:464:in `const_missing'
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:260:in `load_missing_constant'
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:468:in `const_missing'
            from ./test/unit/helpers/cmws_helper_test.rb:9
            from ruby-1.8.5/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
            from ruby-1.8.5/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:495:in `require'
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:342:in `new_constants_in'
            from ruby-1.8.5/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/dependencies.rb:495:in `require'
            from -e:1
            from -e:1:in `each'
            from -e:1

  • Just wind up using recipe 44, it works well in Rails 1.2

  • Is it possible to use ‘assert_select’ against a helper methods output? This would seem to be the natural approach but at first glance I could not assert_select to work for partial ouput.

  • I have found that, in fact, you can use assert_select quite easily. Simply do the following:

    1. Add @response = ActionController::TestResponse.new into the HelperTestCase#setup
    2. In your test case, store the result of the helper method in @response.body

    The following example demonstrates:

    
    class ApplicationHelperTest < HelperTestCase
    
      include ApplicationHelper
    
      def test_checkmark_img
        @response.body = checkmark_img(true)
        assert_select "img" 
      end
    
    end
    

    I also found that when using the content_tag method to generate html, I needed to also include the CaptureHelper and TextHelper modules. By the way, passing a block to content_tag will cause an error when run from the test case. This problem has been documented.

  • Matt Sanders

    Great stuff. In case it helps anyone else, on a machine that still had ruby 1.8.4 on it we were seeing:

    Unable to map class ApplicationHelperTest to a file

    Come up during test runs. Upping to 1.8.6 fixed this, so I assume something changed in the standard lib test/unit.

  • Matt Sanders

    Hmm. My last comment was wrong, that error actually seems to be related to running the tests with autotest (ZenTest) and it not being able to find the test to re-run it.

    Also, I noted that while this post says it was published 6/13/07 it isn’t actually current and shows up on your archive page as from April 2006? Can anyone toss a pointer to whatever the most current suggested method of testing helpers is?

    Thanks much.

  • topfunky

    That error is indeed with Autotest, but there’s a better way. The ZenTest gem includes Test::Rails, which is capable of testing your helpers separately from your views.

    Or, rSpec has Helper spec’ing built-in.

  • Matt Sanders

    Thanks!

  • I am unable to figure out how to get ZenTest to actually do any kind of real testng with helpers.

    Could you give a pointer or two?

  • This broke for me upgrading from 2.0.1 -> 2.0.2 … setup method does not get called with Test::Unit. Haven’t been able to figure out any more yet, unfortunately. Ugly work around is to call a setup method in each test case. You can’t call this method ‘setup’ either, so maybe it’s getting aliased somewhere.

  • Did some more looking, it seems rails is aliasing the setup method in vendor/rails/activerecord/lib/active_record/fixtures.rb which I suspect is causing issues. In my helper, I changed the ‘setup’ method to ‘setup_with_fixtures’ (making sure I called super) and everything is fine. ‘setup’ in HelperTestCase still gets called.

  • topfunky

    @Xavier: Thanks for the troubleshooting. I’ll look into this tomorrow and issue an update.

  • Did some more research, maybe this will help: Test setup broken in Rails 2.0.2

  • script/plugin install helper_test

    times out

  • And then once I get past the timing out issues, I get this:

    test/helper_testcase.rb:4: uninitialized constant ApplicationController (NameError) from ./test/unit/../test_helper.rb:4:in `require’ from ./test/unit/../test_helper.rb:4 from ./test/unit/form15_test.rb:1:in `require’ from ./test/unit/form15_test.rb:1 from /var/lib/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb:5:in `load’ from /var/lib/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb:5 from /var/lib/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb:5:in `each’ from /var/lib/gems/1.8/gems/rake-0.8.1/lib/rake/rake_test_loader.rb:5 rake aborted! Command failed with status (1): [/usr/bin/ruby1.8 -Ilib:test ”/var/lib/gems…]

    (See full trace by running task with—trace)

  • topfunky

    RSpec has built-in helper tests now, so you may not need this anymore.

    Here’s the full link to the plugin:

    http://topfunky.net/svn/plugins/helper_test/

  • S. Brent Faulkner

    Rails has the built-in ActionView::TestCase now too. So you can…

    class MyHelperTest < ActionView::TestCase
      tests MyHelper
      ...
    end

    Just add require ‘action_view/test_case’ in test_helper.rb to enable it.

  • Ilya

    Hi!

    Is there any caveats in fixtures loading in helper tests? I got strange errors while using helper test, but everything is fine while using functional tests.

Your Comment

Nuby on Rails

Geoffrey Grosenbach / Ruby / Code / Graphics / Design / Rails / Merb / Javascript / CSS

Manufactured with

Subscribe

Subscribe (RSS)