LoginSignup
27
24

More than 5 years have passed since last update.

【Rails5, Rspec】Deviseによる認証ありのAPIテスト

Last updated at Posted at 2017-02-14

Rspec、特にrequest specにdevise認証判定を持たせたいときの記事です。

先人の方々が記事にはしてくれているのですが、Rails5になったりDeviseにもアップデートがあったりでいくらかは有益そうだったこと+自分の勉強のためにここに記します。

動いてみると当たり前ではありますが、冷静になってドキュメントを読まないと痛い目をみますね。

動作環境

rails 5.0.1
rspec 3.5.x
devise 4.2.0

RspecのIntegrationTest事情 with Devise

request specが結合テストに用いられるという記述や、capybaraが少し前までrequest spec推奨だったことなどから複雑に考えてしまいました。

RelishのRspecの項目とか公式のWikiのIntegrationTestの項目に以下のように記載がありました。

  • request specはRailsの統合テストについてのthinラッパーを提供する

Request specs provide a thin wrapper around Rails' integration tests, and are
designed to drive behavior through the full stack, including routing
(provided by Rails) and without stubbing (that's up to you).

  • capybaraを用いた結合テストにはDevise::Test::IntegrationHelpersではなくWarden::Test::Helpersを用いる

To do this, you'll need to include warden test helpers and turn on test mode.

ということでrequest specの場合DeviseのTestHelperは使えず、Warden::Test::Helpersにあるlogin_asを利用することになるかと思ったのですが、capybaraとか使ってない普通のAPIのテストであればDevise::Test::IntegrationHelpersにあるsign_inで対応可能でした。

実装

deviseのインストールやcontrollerへの権限設定は済んでいるものとしてrspec周りについて記します、また認証はuserモデルに付与しているものとしてください。テストデータはfactory girlで作ってます。

特に大きいmoduleでもないのですが、そのうち使いまわせるようになるという期待も込めてsupport以下にAuthenticattionMacrosとしてモジュール化しました。

support/authentication_macros.rb
module AuthenticationMacros
  def login
    let(:user) { build(:user) }
    before do
      sign_in user
    end 
  end
end

rails_helper.rbでヘルパーとモジュールの読み込み等を行います。

rails_helper.rb
#中略
require 'devise'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
#中略
RSpec.configure do |config|
  config.include Devise::Test::IntegrationHelpers, type: :request
  config.extend AuthenticationMacros
#中略

最後に認証がかかったAPIに対するリクエストスペックです。

requests/pages_request_spec.rb
require 'rails_helper'

RSpec.describe 'Pages', type: :request do
  describe 'GET #index' do
    context 'with authentication' do
      login
      it 'return success status' do
        get '/pages'
        expect(response).to have_http_status(:success)
      end
    end
    context 'without authentication' do
      it 'return fail status' do
        get '/pages'
        expect(response).to have_http_status(302)
      end
    end
  end
end

所感

テストコードも肥大化してくると書くのが楽しくなりそうだなと思いました。
GitHubにコードを置いておいたので参考までにどうぞ!

27
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
24