今まで、機能テストで、1つのテストメソッドの中で何回もリクエストを送るコードを書いていたことがありました。テストケースを1メソッドに割り当てると、どうしてもrake が重くなったり、メソッドが増え過ぎたりとあって、index アクションの処理はtest_index 内で書くとかしてました。
def test_index #empty parameters get :index assert_template "index" assert_nil assigns(:hoge) get :index, :hoge => 1 assert_template "index" assert_equal "1", assigns(:hoge) end
ひどいときだと、ループの中にget メソッドがあったりしました。例えば、全てのメソッドの前にフィルタ処理が効いているか確かめるとか。
def test_filter methods = @controller.public_methods(false) - ["rescue_action"] methods.each do |method| get method assert_redirected_to :action => "index" assert_equal "please login", flash[:error] end end
そもそもこのテストが有益かどうか怪しいです。
1つのテストメソッドで複数のリクエストを送ると危険
例えば、次のテストは見事に落ちます。
def index @hoge = params[:hoge] if params[:hoge] end def test_index get :index, :hoge => 1 assert_template "index" assert_equal "1", assigns(:hoge) #empty parameters get :index assert_template "index" assert_nil assigns(:hoge) end
通常は、リクエストの度に新しいコントローラのインスタンスが生成されるので、2回目のリクエストでは、@hoge の値はnil になります。しかし、テストの場合は、同じメソッド内で複数回のリクエストを行うと、以前の処理結果が残っている状態になります。よって、2回目のリクエストの際には@hoge の中に最初のリクエストの結果が残ってしまっています。
このことを意識しておかないと、誤ったテストを書いてしまう可能性があります。
回避方法
回避方法は2つあります、1つ目は言うまでもなく、メソッドを2つに分ける方法です。そして、もう1つは、以下のように、get の前でsetup メソッドを呼ぶことです。
def test_index get :index, :hoge => 1 assert_template "index" assert_equal "1", assigns(:hoge) #empty parameters setup get :index assert_template "index" assert_nil assigns(:hoge) end