Test helpers for Rails

In Rails, I occasionally find myself needing to share some specific functionality between tests. I usually take advantage of Ruby’s remarkable modules and make a module which defines the functionality that I need. I then use the include class method to import the functionality into the test case where I need it. When I create a module like this I call it a test helper.

For example, in my current project I have a Page model object for which I created the following test helper (abbreviated):

module PageTestHelper
  VALID_PAGE_PARAMS = {
    :title => 'New Page',
    :slug => 'page',
    :breadcrumb => 'New Page',
    :status_id => '1',
    :parent_id => nil
  }
  
  def page_params(options = {})
    params = VALID_PAGE_PARAMS.dup
    params.merge!(:title => @page_title) if @page_title
    params.merge!(:status_id => '5')
    params.merge!(options)
  end
end

In a test case, when I need access to the methods on the PageTestHelper module I just include it:

require 'test/helpers/page_test_helper'

class PageTest < Test::Unit::TestCase
  include PageTestHelper

  def setup
    @page = Page.new page_params
  end

  # etc...
end

My naming convention for test helpers is that they always include TestHelper in their module name. Sometimes I forget to include Test in the name when I include it in a test case which causes an error. Sometimes I forget to require the file which the test helper is stored in which also causes an error. This happens quite frequently.

Recently, I decided to make things easier on myself. In test_helper.rb (found in the test directory of every rails project) I inserted the following code:

require 'pathname'
TEST_ROOT = Pathname.new(
  File.expand_path(File.dirname(__FILE__))
).cleanpath(true).to_s

# Auto require test helpers
Dir[TEST_ROOT + '/helpers/**/*_helper.rb'].each do |helper|
  require helper
end

Also, amongst the other code that modifies Test::Unit::TestCase in test_helper.rb I added a test_helper class method:

# Class method for test helpers
def self.test_helper(name)
  name = name.to_s
  name = $1 if name =~ /^(.*?)_test_helper$/i
  constant = Inflector.constantize(Inflector.camelize(
    Inflector.singularize(name.to_s) + '_test_helper'))
  self.class_eval { include constant }
end

This was my first chance to use the marvelous Inflector class that Rails provides. It certainly makes it much easier to write class methods that work with symbols.

Now, when I need to use a test helper in a test case I do something like this:

class PageTest < Test::Unit::TestCase
  test_helper :pages

  def setup
    @page = Page.new page_params
  end

  # etc...
end

Meta-programming is marvelous. I no longer need to remember to require my test helpers and the test_helper class method removes the verbosity from the include. Much, much better.

How are you making testing easier for yourself in Rails?

© 2013 John W. Long