After my shameful post earlier, Tom Ward put me back on the straight and narrow by suggesting that I try creating a sub-class of Test::Unit::TestCase to avoid overriding send(). Here's my initial stab:

class FunctionalTest < Test::Unit::TestCase
   def run(result)
    controller_name = self.class.to_s.gsub('Test','')
    if controller_name != 'Functional'
      @controller = eval("#{controller_name}.new")
      @request    = ActionController::TestRequest.new
      @response   = ActionController::TestResponse.new

      @request.host = "curve21.mymagicalapp.com"
      @request.session[:current_user_id] = 1
    end

    if @method_name.to_s == "default_test"
      false
    else
      super(result)
    end
  end
end

There's obviously loads to tidy up here, but I now have the functionality in one place that can be expanded easily. With this method, each functional test can still happily have it's own set up and even override the values setup here.

Ultimately I'll add some configuration so this class can be used in other applications, but for now this has DRYed up my controller tests quite a bit and allowed me to specify the shared data:

class DashboardControllerTest < FunctionalTest
  def test_should_show_dashboard
    get :index
    assert_response :success
  end
end

Just to clarify, the reason for setting this 'global test data' is that my application is reliant on the URL to identify a user and account on the system. Most of the tests work within that context: Add a user to this account, delete a widget from this account etc etc. As such they just need a test account to work from. I therefore setup the @request.host value to contain one of the URLs from my fixtures.

For the tests where I _do_ need a specific URL (like access control), I can override in the specific method:

class UserController < FunctionalTest
  def test_should_not_show_someone_elses_user
    @request.host = 'another.magicalapp.com'
    get :edit, :id => 1
    assert_response :redirect
  end
end

Also, as the setup() method is called for a test before each method is run, anything set in that method overrides the base values:

def setup
  @request.host = 'another.magicalapp.com'
end

1 Response to “DRYing up my functional tests”

  1. Jamie Macey Says:

    Stephen, have a look at Test::Rails in the ZenTest gem - it allows you to specify Controller Tests and View Tests. You might find it useful, or at least something to compare your stuff with.

Sorry, comments are closed for this article.