Rubyと筋肉とギターとわたし

筋トレが仕事です

【Rails】RSpecでcontrollerを書く際、deviseのauthenticate_userに毎回弾かれるときの対処法

どうもてぃです。

お久しぶりです。皆さん元気にしてましたか?

私は最近新居を建てる契約しまして、家計は火の車確定、毎日趣味の時間を犠牲になんとかお仕事を頑張って稼いでる次第であります。

はたして、この生活も何年もつことやら…。

本題

題のとおりです。公式を参考にしても弾かれて、まともなresponseが返ってこなかったので、一日時間を無駄にしました。

そのため久しぶりの記事行き。積み記事たくさんあるんですけどね。

rspec実行時が以下の状態。

% docker-compose run --rm -e RAILS_ENV=test web bundle exec rspec ./spec/controllers/tests_controller_spec.rb 
Starting project_1 ... done
F

Failures:

  1) TestsController GET show response status 200
     Failure/Error: expect(response.status).to be 200
     
       expected #<Integer:401> => 200
            got #<Integer:803> => 401
     
       Compared using equal?, which compares object identity,
       but expected and actual are not the same object. Use
       `expect(actual).to eq(expected)` if you don't care about
       object identity in this example.
     # ./spec/controllers/tests_controller_spec.rb:13:in `block (3 levels) in <top (required)>'

Finished in 0.12308 seconds (files took 1.13 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/controllers/tests_controller_spec.rb:11 # TestsController GET show response status 200

一応sign_in等の設定を行っているんですが、このありさま。

以下、環境や設定について書いていきます。

環境

  • docker-compose version 1.25.4, build unknown
  • Docker version 19.03.6, build 369ce74a3c
  • Ruby 2.5.0
  • Rails 5.2.1

エラー時の設定

# spec/support/controller_macros.rb

module ControllerMacros
  def login_user(user)
    @request.env['devise.mapping'] = Devise.mappings[:user]
    sign_in user
  end
end

sign_in用のメソッドをモジュール化。

# spec/rails_helper

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

RSpec.configure do |config|
.
.
.
.
config.expect_with :rspec do |c|
  c.syntax = :expect
end
config.include Devise::Test::ControllerHelpers, type: :controller
config.include ControllerMacros, type: :controller
config.include Warden::Test::Helpers
.
.
end

devise用にrails_helperへの設定を追加。

実際にテストで使用してみる。

require 'rails_helper'

RSpec.describe TestsController, type: :controller do
  let(:test) { create(:test) }
  let(:user) { test.test_category.user }
  let(:company) { create(:company) }

  describe 'GET show' do
    before { login_user user }

    it 'response status 200' do
      get :show, params: { id: test.id }
      expect(response.status).to eq 200
    end
  end
end

これを実行してみた結果が最初のエラーです。

login_userメソッドのタイミングを変えたりいろいろ試してみたんですが、結局ダメでした。

対処法

いろんな記事のものを試してみたんですが、全くうまくいかずstackoverflowに同じようなエラー出てる人がいたので、参考にして設定を追加。

以下のリンク

stackoverflow.com

controller_macros.rbrails_helper.rbを変更。

module ControllerMacros
  def login_user(user)
    @request.env['devise.mapping'] = Devise.mappings[:user]
    controller.stub(:current_user).and_return(user)
    sign_in(user, scope: :user)
  end
end
.
.
.

RSpec.configure do |config|
.
.
.
.

  # devise setting
  config.expect_with :rspec do |c|
    c.syntax = :expect
  end
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::IntegrationHelpers, type: :request
  config.include ControllerMacros, type: :controller
  config.include Warden::Test::Helpers
.
.
end

これでテストを実行すると、 設定しているauthenticate_user!に引っかからず、controllerテストが動くようになりました。

終わりに

新居のローン返済が怖いので誰かお仕事ください。