Redmine 3.x(Rails 4.2)までは、コントローラーの雛形を生成する際に一緒に生成される機能テスト(functional)のテストコードではActionController::TestCaseを継承していました。
class TermCategoriesControllerTest < ActionController::TestCase
Redmineを離れて、Rails 5ではコントローラーの雛形を生成する際に一緒に生成されるコントローラーのテスト(controller)のテストコードではActionDispatch::IntegrationTestを継承します。
class SomethingsControllerTest < ActionDispatch::IntegrationTest
ただし、Redmine 4.0(開発途上版 trunkブランチ)のコントローラー生成タスクでは従来どおりActionController::TestCaseを継承したテストコードが生成されます。
Redmine 4.xのプラグインにおけるコントローラーのテストで、ActionDispatch::IntegrationTestを使うとどうなるのかを探ってみます。
ActionDispatch::IntegrationTestの場合
コントローラーの一番単純なテストケースは、indexアクションを呼び出しHTTPステータスの成功が返ってくることになります。
ActionController::TestCaseを継承したテストクラスでは、次の様に記述していました。
class TermCategoriesControllerTest < ActionController::TestCase def test_index get :index, params: { project_id: 1 } assert_response :success end end
しかし、ActionDispatch::IntegrationTestを継承したテストクラスでこの記述のままだと実行時にエラーとなります(おかしなURLパスが生成されます)。
Error: TermCategoriesControllerTest#test_index: URI::InvalidURIError: bad URI(is not URI?): http://www.example.com:80index
getメソッドの第1引数 :index が、ホスト(なぜかhttp://www.example.com:80)に直接付いてしまっています。ActionDispatch::IntegrationTestではURLパス(URLからホスト名:ポート番号までを除いた残り)を指定しなくてはならないようです。
URLパスを指定する方法(1)
ルーティング設定でresources/resourceを指定していると、名前付きルーティングが生成されるので、ヘルパーメソッドで指定が可能です。しかし、今回getで生成しているのでデフォルトでは名前付きルーティングが生成されません。
プラグインのconfig/routes.rbで次のように記述していると、
get '/projects/:project_id/term_categories', to: 'term_categories#index'
生成されるルーティングは次のようになり、名前付きルーティングはありません。
GET /projects/:project_id/term_categories(.:format) term_categories#index
プラグインのconfig/routes.rbで次のようにasで名前を指定すると、
get '/projects/:project_id/term_categories', to: 'term_categories#index', as: 'project_term_categories'
生成されるルーティングは次のように、名前付きルーティングが設定されます。
project_term_categories GET /projects/:project_id/term_categories(.:format) term_categories#index
class TermCategoriesControllerTest < ActionDispatch::IntegrationTest def test_index get project_term_categories_url, params: { project_id: 1 } assert_response :success end end
URLパスを指定する方法(2)
名前付きルーティングがない場合、URLパス文字列を自前で構成する方法があります。
get "/projects/#{@project.id}/term_categories", params: { project_id: 1 }
ユーザーの指定方法?
ログインが必要となるプラグイン機能のテストでは、ログイン情報を持たないでテストを実行すると、ログイン画面へのリダイレクトが発生し、テスト結果が成功ではなく302(リダイレクト)となっています。
ActionController::TestCaseでは、@request.session にユーザー情報を入れてログイン状態でのテストを実施できました。
ActionDispatch::IntegrationTestでは、post でログインをしてから対象テストを実施するようです。
ログインのHTTPメソッド(POST)を送ってからコントローラーのアクションに対応するHTTPメソッドを呼ぶのですが、ログイン情報の引継ぎの方法などが分かりません。
このあたりのノウハウが欲しいところです。