In functional tests a controller instance should not be reused: usually controller instances hold some state, that gets discarded in the normal Rails life cycle, and our tests must reflect that. Otherwise, tests can fail even if they shouldn’t, but even worse tests could succeed when they shouldn’t.
See this testcase:
require File.dirname(__FILE__) + '/../test_helper' class DuuController < ActionController::Base def index @test ||= params[:test] render :text => @test, :layout => false end end class DontUseAControllerTwiceInATestcaseTest < ActionController::TestCase def setup @controller = DuuController.new ... end def test_with_strange_results get :index, :test => "duu1" assert_equal("duu1", @response.body) get :index, :test => "duu2" assert_equal("duu1", @response.body) # !!Watch this!!! end end
This, of course, matches the Rails lifecycle of objects during an action: Rails creates a controller instance for each incoming request, and throws it away afterwards. This again matches the stateless behaviour of HTTP connections: each action response starts with a clean sheet. And wonderfully enough this ensures that all memory used by the response is cleaned up afterwards (unless you shoot yourself in our foot, of course, and if the ruby interpreter plays along nicely.)
If you need a series of simulated requests in a single test then you must recreate the @controller object from scratch:
def test_duu2 get :index, :test => "duu1" assert_equal("duu1", @response.body) @controller = DuuController.new get :index, :test => "duu2" assert_equal("duu2", @response.body) # !!Watch this!!! end
To be honest I have no idea why rails best practices apparently recommend this. A simple change, and we could happily write
class SmarterTestingTest < ActionController::TestCase testing :duu_controller ... end
No setup needed, at least not the boilerplate part. Remember DRY?