Auth0のJWT認証をRspecのスタブを使ってテスト
Rspec で JWT 認証をする場合、テストをパスするには実際にユーザーが使っている JWT トークンをセットしなければなりません。
しかしユーザーの認証トークンを使っていて尚且つ、特定の値に依存するようなテストを書くのは望ましくないです。
今回は Rspec のスタブを使ってそれを回避します。
コントローラーでは以下のような認証コードを書いています。
class SecuredController < ApplicationController
before_action :authorize_request
private
def authorize_request
authorization = Authorization::AuthorizationService.new(request.headers)
@current_user = authorization.current_user
rescue JWT::VerificationError, JWT::DecodeError
render json: { errors: ['Not Authenticated'] }, status: :unauthorized
end
attr_reader :current_user
end
ログインユーザーしか実行できないアクションではbefore_action :authorize_request
によってアクションの実行前にauthorize_request
が実行される仕組みです。
そして以下の部分で、ログインユーザーを呼び出すための認証を行なっているのですが Rspec を書く際、存在するトークンを使わずにどうやってテストをパスするか考えなくてはいけません。
@current_user = authorization.current_user
上記の問題を Rspec のスタブを使って解決します。
current_user
メソッドが実行された際に、Rspec 側で用意したcurrent_user
を返すスタブを作成します。
以下のモジュールを作成して読み込みます
module AuthorizationHelper
def authorization_stub
allow_any_instance_of(SecuredController).to receive(:authorize_request).and_return(current_user)
allow_any_instance_of(SecuredController).to receive(:current_user).and_return(current_user)
end
end
RSpec.configure do |config|
config.include AuthorizationHelper
.
.
end
authorize_request
メソッドとcurrent_user
メソッドが呼び出された時、それぞれに対して rsepc 側で作成したcurrent_user
を返すようにしました。
テストの一例は以下のようになります。
RSpec.describe '推しメン登録機能 Api::V1::Users::RecommendedMembers', type: :request do
let!(:current_user) { create(:user) }
before do
# authorize_requestメソッドが呼ばれたらlet!(:current_user)を返す。
# SecuredControllerのcurrent_userメソッドが呼ばれたらlet!(:current_user)を返す。
authorization_stub
end
describe 'ユーザーが推しメンを閲覧 GET api/v1/user/recommended_members' do
let(:recommended_member_num) { 5 }
let(:http_request) { get api_v1_user_recommended_members_path}
before do
create_list(:recommended_member, recommended_member_num, user: current_user)
end
context '正常系' do
it '推しメンを閲覧できること' do
http_request
expect(body['data'].count).to eq(recommended_member_num)
expect(response).to be_successful
expect(response).to have_http_status(:ok)
end
end
end
end
以下のコードによって先ほどのスタブを呼び出しています。
before do
# authorize_requestメソッドが呼ばれたらlet!(:current_user)を返す。
# SecuredControllerのcurrent_userメソッドが呼ばれたらlet!(:current_user)を返す。
authorization_stub
end
そしてhttp_request
を実行しauthorize_request
メソッドとcurrent_user
メソッドが呼び出された時、それぞれに対して rsepc 側で作成したcurrent_user
を返しています。
let!(:current_user) { create(:user) }
.
.
.
let(:http_request) { get api_v1_user_recommended_members_path }
.
.
.
http_request
解説は以上になります。
ここまで、読んでいただきありがとうございました!
分かりにくい、または間違っているところあれば連絡いただければと思います。
何か連絡をしたい際は以下 SNS、メールでお願いいたします。
Twitter: https://twitter.com/naka_ryo_z
見出しへのリンク