rspecのテスト環境でdeviseにログインする方法【rails】


やりたいこと

rspecを使ったテストの中でcurrent_userとかを使いたい

方針

テストの中で、deviseのログイン状態を擬似的に作る。

具体的にはuserのデータを生成し、ログインをbefore doの中で行う。

導入したgem

gem 'devise'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'faker'
gem 'rails-controller-testing'

railsのバージョンによってはrails-controller-testingは、Gemfileに記述を書いてbundle installしても入らないことがあるっぽいです。
その時は下記をどうぞ。

$ gem install rails-controller-testing

下記を試せば、gemの名前にconが含まれるものだけ検索できて、導入できたか確かめられます。

$ gem list con
=> rails-controller-testing (1.0.1)

公式ドキュメント:rails/rails-controller-testing


どうやるか

  • support/controller_macrosを作成、ログインのためのコードを記述
  • rails_heplerにdeviseとmacrosの読み込みを記述
  • spec/factories/user.rbの作成
  • controllerにbefore doを記述しログインさせる

実装

1. controller_macrosの作成

spec/support/controller_macros.rbを作成し、下記の内容を追記してください。

spec/support/controller_macros.rb
module ControllerMacros
  def login_admin(admin)
    @request.env["devise.mapping"] = Devise.mappings[:admin]
    sign_in admin
  end

  def login_user(user)
    controller.stub(:authenticate_user!).and_return true
    @request.env["devise.mapping"] = Devise.mappings[:user]
    sign_in user
  end
end

2. rails_helper内でdeviseとcontroler_macrosを読み込む

rails_helperのRSpec.configure外に以下を記述し、deviseとmacrosを読み込みます。

spec/rails_helper.rb
require 'devise'
require File.expand_path("spec/support/controller_macros.rb")

RSpec.configure内に以下を記述し、deviseのtest_helperとmacrosをcontroller内で使えるようにします。

spec/rails_helper.rb
RSpec.configure do |config|
  config.include Devise::TestHelpers, type: :controller
  config.include ControllerMacros, type: :controller
end

3. FactoryGirlとFakerを使い、userモデルを作成

以下を記述することで、FactoryGirlを使う時に記述を減らすことができます。

rails_helper.rb
RSpec.configure do |config|
    config.include FactoryGirl::Syntax::Methods
end
# 記述なし
FactoryGirl.create(:user)

#記述あり
create(:user)

FactoryGirlで使うuserのモデルを作成します。

Fakerを使い、全てのデータを生成しています。
passwordとpassword_confirmationを同じデータにするために、passを定義してそれを代入する形となっています。

spec/factories/user.rb
FactoryGirl.define do
  pass = Faker::Internet.password(8)

  factory :user do
    name                  Faker::Name.name
    email                 Faker::Internet.email
    password              pass
    password_confirmation pass
  end
end

4. controller_spec.rbで、userをcreateしログイン処理をする

createしたuserをletに格納しインスタンス変数のように使用できるようにしました。
さらにそのuserにlogin_userメソッドを使ってdeviseにログインさせます。

message_controller_spec.rb
require 'rails_helper'

describe MessagesController, type: :controller do
  let(:user) { create(:user) }
  # userをcreateし、let内に格納

  describe 'GET #index' do
    before do
      login_user user
      # controller_macros.rb内のlogin_userメソッドを呼び出し
    end

    it "renders the :index template" do
    end
end

何ができるようになったか

current_userなど、deviseのヘルパーメソッドを使用したインスタンス変数のテストが出来るようになりました。

message_controller.rb
  def index
    @groups = current_user.groups
  end

上記のコードはアソシエーションを組まないと動かないのですが、
RSpecテスト内でのアソシエーションの組み方はこちらをどうぞ。

番外編;最近買った、面白いもの

・ハンターハンター34巻(6/29)
クロロ VS ヒソカとか、どうやっても面白くなるとしか
・カーテン自動開閉ロボット
カーテンレールに付ける4000円のロボット。
これを付けてから目覚ましなしで起きられる率が上がった。
・衛藤美彩 写真集
「綺麗なお姉さん」が好きな人、ちょっと眺めてるだけで幸せになれますよ。

参考サイト様

deviseで認証しているログイン必須のRspec controllerテスト

deviseを使ったコントローラのテスト