はじめに
ApplicationController
では、ユーザーのロール(役割)に対して、アクセス制御を行っていると思います。
では、そのアクセス制御をテストしようと思った時に、どのように実装しますでしょうか?
- requestテストでやろう!
- でも、
ApplicationController
へのルーティングは通っていないよね...
- でも、
- アクセス制御をしている箇所を
Concern
に切り分けて、単体テストでやろう!- これは結構良さげ
- ただ、切り分けるほどの処理の大きさでもない...
上記のように、色々と模索すると思います。
その中で、AnonymousController
を使用すれば、実装を変えずにテストすることができます。
今回はその内容をアウトプットいたします。
Rails5からは、request spec
が推奨されています。
今からは、controller spec
になるので、ご了承ください。
AnonymousController とは
controller
メソッドを使用して、匿名コントローラーを作成することができます。
明示的にコントローラーを渡すこともできますし、ルーティングも自動に設定してくれます。
実装
require 'rails_helper'
RSpec.describe ApplicationController, type: :controller do
controller(ApplicationController) do
def index
render plain: "OK"
end
end
describe '#authorize_access' do
before do
sign_in test_user
end
subject { get :index }
context 'when the user has permission' do
let(:test_user) { create(:test_user, role: 'editor') }
it 'returns http success' do
is_expected.to have_http_status(:success)
end
end
end
end
解説
今回の例では、ApplicationController
のbefore_action
で定義しているメソッドをテストしています。(※ アクセス制御の部分)
get :index
を実行すると、実際のApplicationController
を実行してくれます。
なので、すごくテストがしやすいです。
以下にも、解説や注意点をまとめました。
type: :controller
は忘れずに
ここを、type: :request
にしていると、controller
メソッドは使用できません。
type
は、controller
を必ず指定しましょう。
ルーティングは自動で設定される
controller
メソッドを使用して、匿名コントローラーを作成しているので、ルーティングの設定が必要になるかと思っていました。
ただ、親切に、AnonymousController
は、自動で設定してくれます。
※ 明示的に、ルーティングの設定を記載しても問題ありません。
今回だと、index
メソッドを用意したので、get :index
と実装すれば、通るようになります。
controllerへの引数を渡すこともできる
今回はdescribe
で指定しているコントローラーと差異はないので、controller(...)
と引数を渡さなくても、問題ないかと思います。
ただ、明示的に渡して、特定のコントローラーで実装することも可能です。
Deviseの設定は、rails_helper
に忘れずに (※ この記事限定)
今回の実装例では、sign_in
メソッドを使用しています。
これは、Deviseのヘルパーメソッドになるので、controller spec
で使用できるように、設定が必要になります。
config.include Devise::Test::ControllerHelpers, type: :controller
上記を忘れずに設定しましょう。
まとめ
実装始めは、type
をrequest
にしていて、controller
メソッドが使用できず、悪戦苦闘していました...。
ただ、実際に使用してみて、ApplicationController
のテストには、すごく向いているなと思いました。
他のコントローラーのテストは、request spec
で十分です。
今回は、AnonymousController
で実装しましたが、他にも良い実装があれば、教えていただきたいです。
最後までご覧いただき、ありがとうございました。