質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

ログイン

ログインは、ユーザーがコンピューターシステムにアクセスするプロセスの事を呼びます。

Q&A

解決済

1回答

8780閲覧

rspecでログイン状態(session値の設定)を再現する方法について

Harluz

総合スコア19

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

ログイン

ログインは、ユーザーがコンピューターシステムにアクセスするプロセスの事を呼びます。

0グッド

0クリップ

投稿2020/12/27 02:33

編集2020/12/27 09:38

rails tutorialを参考にログイン機能やbefore_actionにてログイン済みのみができるアクションを実装しました。
そのテストコードにおいてログインの有無の2パターンでテストを実行したいと思います。

ログインをしていない場合は、単純に制限のあるURLをgetすれば再現できると考えています。
ログインしている場合は、postリクエスト及び必要情報を渡すことでログインを再現できるのではないかと思います。
このことから、下記の通りにテストコードを記述して見ました。が、rspecのログを確認するとログインできていない動作になっております。

helperにてログイン状態を再現するメソッドを定義

testhelper

1include ApplicationHelper 2 3module TestHelper 4 def log_in_as(user, remember_me: '1') 5 post login_path, params: { session: { 6 email: user.email, 7 password: user.password, 8 remember_me: remember_me 9 } } 10 end 11end

テストヘルパーを全てのスペックで使用できるようにinclude済み

railshelper

1RSpec.configure do |config| 2 config.include TestHelper 3end

factorybot

1FactoryBot.define do 2 factory :user, class: :user do 3 name { Faker::Name.name } 4 sequence(:email) { |n| "example#{n}@example.com" } 5 image { Rack::Test::UploadedFile.new(File.join(Rails.root, 'spec/fixtures/test.jpg')) } 6 7 password { 'foobar' } 8 password_confirmation { 'foobar' } 9 10 trait :admin do 11 admin { true } 12 end 13 end 14end

UsersRequestSpec

1describe 'GET #index' do 2 subject { response } 3 # ユーザーのログインの有無を確認 4 describe 'before_action :logged_in_user' do 5 let!(:user) { FactoryBot.create(:user) } 6 # ユーザーがログインしている場合 7 context 'The user is logged in' do 8 before do 9 log_in_as(user) ← ログイン状態を再現しているはず 10 get users_path 11 end 12 it 'responds successfully' do 13 is_expected.to be_successful 14 end 15 16 it 'returns a 200 response' do 17 is_expected.to have_http_status(200) 18 end 19 end 20 end

rspecのログ
赤線部分が疑問な箇所になりまして、一本目ではpostした情報を元にuserをログインし、2本目でusers/1(user.id)にアクセスしているのでここまでは期待した動作になっています。しかし、その後にredirectで/loginにアクセスしています。

usercontrollerを下記の通りに示します。(抜粋)

UserController

1before_action :logged_in_user, only: %i[index edit update destroy] 2 3 PER = 10 4 5 def index 6 @users = User.page(params[:page]).per(PER) 7 end 8 9private 10 # ログイン済みユーザーかどうか確認 11 def logged_in_user 12 # ログインしていないのなら 13 unless logged_in? (解説:sessionにuser.idがあればtureを返す。userがログインしたらuser.idを元にsessionに情報が格納される) 14 store_location 15 flash[:danger] = 'Please log in.' 16 redirect_to login_url 17 end 18 end

rsepcのログをみる限りログインできていないことから、before_actionの logged_in_userによってlogin_urlに飛ばされているのだと思います。

どのようにすればこれのテストを再現することができるのでしょうか?
ちなみに、ブラウザ情では期待している動作になっておりますので、問題はないかと思います。

どんな些細なことでも構いませんので、どなたか教えていただければとても助かります。
よろしくお願いします。

neko_daisukiさんの回答より
test_helperを下記のメソッドを追記

testhelper

1def sign_in(user) 2 allow_any_instance_of(ActionDispatch::Request).to receive(:session).and_return(user_id: user.id) 3 end

usersrequestspec

1subject { response } 2 let(:user) { FactoryBot.create(:user) } 3 # ユーザーがログインしている場合 4 context 'The user is logged in' do 5 before do 6 sign_in(user) ← 修正 7 get edit_user_path(user) 8 end 9 it 'responds successfully' do 10 is_expected.to be_successful 11 end 12 13 it 'returns a 200 response' do 14 is_expected.to have_http_status(200) 15 end 16 end

rspecを実行した結果
テスト成功状況
しっかりsessionの値を取得しrenderしていることが確認できます。

neko_daisukiさんの記述していただいたコードでは以前と同じログになったため、下記qiitaの記事を参考にしたところ、成功いたしました。
request spec で session 値を設定する

詳しい挙動等についてはこれから調べるため説明することはできませんが、とりあえず動作することができましたので、同じようにつまづいている方の参考になればと思います。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

たぶん以下の A と B のセッションが別物になってます。

ruby

1log_in_as(user) # A 2get users_path # B

サインイン状態を再現するにはwith_sessionを用いるか以下のようにします。

ruby

1def sign_in(user) 2 allow_any_instance_of(ActionDispatch::Request) 3 .to receive(:session){ { id: user.id } } 4end 5 6sign_in(user) 7get users_path

request spec session などで検索すると関連する情報が見つかります。

投稿2020/12/27 06:34

neko_daisuki

総合スコア2090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Harluz

2020/12/27 09:43

返信が遅くなってしまい大変申し訳ありません。 回答ありがとうございます。これを元に記事を追記しました。 シンプルかつ簡潔に回答いただき助かりました。 本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問