TL;DR
mock class(Controller)を作成して、routingを追加して作成する
なぜrequest specでbefore_action を書くことになったのか
抽象化しているまたは、ApplicationControllerで全てに
適応する、メゾッドのテストを記載しないといけなくなり、controller specは使えず(anonymous controllerは利用できないため)対応を考えた。
想定しているcontroller
application_controller.rb
class ApplicationController < ActionController::Base
before_action :authenticate
def authenticate
// headerからauth処理関係
end
end
上記の問題は(実装もあるがテストで)、ApplicationController をrouting実装されておらず、request specでテストが記述しづらい。
ので、stack overflow
をもとにMockControllerを実装した
application_controller_spec.rb
describe 'Host header attack defense', type: :request do
before do
mock_controller = Class.new(ApplicationController) do
def index
render json: { ok: true }
end
end
stub_const('MockController', mock_controller)
Rails.application.routes.disable_clear_and_finalize = true
Rails.application.routes.draw do
get '/mock', to: 'mock#index'
end
end
after { Rails.application.reload_routes! }
context '#authenticate' do
let(:headers) { { "Content-Type": "application/json" } }
subject { get '/mock', headers: headers }
it { is_expect.to eq 200 }
// 他にわしゃわしゃ
end
end
個人的には結構、汎用性高くて好みです。(test onlyのroutingを記述しなくて済む)。
抽象化した場合(Concerns使ってもええんやで)、ApplicationControllerや継承元となるControllerのテストを書く時楽ちんですが、これ重くなるんじゃない?とも思ってる。
他に書き方あったら教えてください。