はじめに
今参加させていただいているスタートアップでapi実装をしており、認証をfirebase authenticationに頼っているのですが、rspecでテストを行うときにjwtの認証をよしなにスキップする方法でめちゃめちゃハマったのでその備忘録です
元々のコード(説明のためかなり省略しています)
applicatioion_controller.rb
class ApplicationController < ActionController::Base
before_action :authenticate!
private
def authenticate!
if request.headers['Authorization'].present?
jwt = request.headers['Authorization']
# jwtを渡すと検証を行いユーザーの情報を返してくれる独自モジュールを呼び出し
@user_info = Firebase::JwtAuth.authenticate(jwt)
else
render json: { type: '401', message: 'not authorized' }, status: 401
end
end
end
user_controller.rb
class UsersController < ApplicationController
# ユーザー一覧を持ってくる
def index
users = User.all
render json: user status: :ok
end
end
spec/requests/user_spec.rb
describe UsersController, type: :request do
let(:headers) { { CONTENT_TYPE: 'application/json', Authorization: 'hoge_token' } }
describe 'GET /users' do
it '全てのユーザーを取得する' do
# header情報をくっつけてリクエストする
get "/users", headers: headers
# ステータスコード200が返ってくる、、、はずだった
expect(response.status).to eq(200)
end
end
end
問題点
最初はこんな感じで実装してたのですが、、、これだと色々と問題があります
- jwtは有効期限が決められているため、実装した瞬間は通ることはあっても一定の時間が経つと通らなくなってしまう
- テストをするたびにfirebase側に不要なリクエストを送ってしまう
もっとあるとは思いますが、ざっとこんなところでしょうか?
対処法
これの対処法としては
テスト時にauthenticate!
メソッドが呼ばれた時はあらかじめ設定しておいた@user_info
を返すようなスタブを作成するというものです
※スタブってなんぞ?って人は↓この辺を見てあとは自分で調べてくださいw
https://wa3.i-3-i.info/word14933.html
ってことなのでそのスタブを作っていきます
/support/authenticated_helper.rb
module AuthenticationHelper
def authenticate_stub
# 渡したいインスタンス変数を定義
@user_info = [
{
'name' => 'kosuke',
'email' => 'kosuke@example.com',
'email_verified' => true,
}
]
# allow_any_instance_ofメソッドを使ってauthenticate!メソッドが呼ばれたら
# ↑のインスタンス変数を返す
allow_any_instance_of(ApplicationController).to receive(:authenticate!).and_return(@user_info)
end
end
そして作ったスタブをテストコードから呼び出します
spec/requests/user_spec.rb
describe UsersController, type: :request do
let(:headers) { { CONTENT_TYPE: 'application/json', Authorization: 'hoge_token' } }
describe 'GET /users' do
it '全てのユーザーを取得する' do
authenticate_stub # ←追記
# header情報をくっつけてリクエストする
get "/users", headers: headers
# ステータスコード200が返ってくる
expect(response.status).to eq(200)
end
end
end
こうしてあげることでauthenticate!
メソッドが呼ばれた時に用意しておいたインスタンス変数が帰るので
無事テストを通すことができます
以上!