LoginSignup
1
0

More than 3 years have passed since last update.

【Rspec】requests spec・コントローラーのテストについて〜adminユーザー作成やeditアクションのテスト〜

Last updated at Posted at 2021-03-06

requests spec・コントローラーのテストについての話

モデルと結合テストは問題なく終わり、コントローラーのテストについてあれこれ調べていたがなかなか自分に理解できるものがなく、困っていました。
公開されているGitHubのコードを見てもコントローラーのテストコードをやっている人が少なかったというのも一つの要因なのですが、試行錯誤してなんとか完成しました。
正直これでいいのかちょっとわからない部分もあるので、もし知見がある方がこの記事を見て下さったらコメント頂けると嬉しいです。

adminユーザーの生成で困ったこと

DBにadminカラムを作ってtruefalseかで判別しています。
FactoryBotでユーザーを生成するために書いたコードが下記のものです。

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname              { '野比のび太' }
    sequence(:email)      { |n| "tester#{n}@example.com" }
    password              { 'q11111' }
    password_confirmation { password }
    profile               { 'なんとかしてよドラえもん' }
    admin                 { false }    ⬅️一般ユーザー
  end

  factory :admin_user do
    nickname              { 'ドラえもん' }
    sequence(:email)      { |n| "tester#{n}@example.com" }
    password              { 'a11111' }
    password_confirmation { password }
    profile               { 'いつまでも子供じゃないんだよしっかりしろよ' }
    admin                 { true }     ⬅️adminユーザー
  end
end

そしてusers_spec.rbには以下のように記述。

spec/requests/users_spec.rb

RSpec.describe UsersController, type: :request do
  let(:user) { FactoryBot.create(:user) }
  let(:admin_user) { FactoryBot.create(:user, admin: true) }
 #let(:admin_user) { FactoryBot.create(:admin_user) }⬅️この書き方でもダメでした

これでadminユーザーが作成されるはずだと思っていたのですがbinding.pryで止めて中身を見るとadmin_userが作成されていませんでした。
色々書き方を変えてやってみたところ、letを使わずにbefore doにしたらうまくいきました。

spec/requests/users_spec.rb
RSpec.describe UsersController, type: :request do
  before do
    @user = FactoryBot.create(:user)
    @admin_user = FactoryBot.create(:user, admin: true)
   #@admin_user = FactoryBot.create(:admin_user)⬅️この書き方でもダメでした
  end

3c9fb0574c103d376e614707e02c1126.png

ひとまずこれで一般ユーザーとadminユーザーを分けることができるようになりました。

editアクションのテストで困ったこと

コントローラーのテストをする上でまず困ったのがeditアクションのテストでした。
authenticate_user!を使用しているためコントローラーのテスト実行時に、
「ログインしていないユーザー」とみなされてしまってリダイレクトされてしまうのです。
リクエストが正常のレスポンスではなくなってしまうと、テスト項目の
expect(response.status).to eq 200
ここの200が302になってしまいます。

また、編集できる時とできない時、両方のテストをしなければいけないため、コントローラーのテストコード上でログインをさせることができれば正常な返り値が得られると考えました。

deviseのメソッドをテストコード上でも使えるようにするには

テストコード上でログインさせるメソッドとして結合テストコード時に使っていたmoduleでやってみたところ、うまくいきませんでした。
調べた結果、コントローラーのテストではdeviseのメソッドを使用できるとのことだったのでそちらに切り替えました。

spec/rails_helper.rb
RSpec.configure do |config|
  #deviseのsign_inメソッドが使えるようになる
  config.include Devise::Test::IntegrationHelpers, type: :request
end

これでsign_inというメソッドが使用できるようになりました。
自分の場合は@userと定義しているのでそのまま使います。

spec/requests/users_spec.rb
require 'rails_helper'
RSpec.describe UsersController, type: :request do
  before do
    @user = FactoryBot.create(:user)
  end

  describe 'GET #edit' do
    context 'userがログインしているとき' do
      before do
        sign_in @user  ⬅️ここでログイン
      end
      it 'editアクションにリクエストすると正常にレスポンスが返ってくる' do
        get edit_user_path(@user)
        expect(response.status).to eq 200  ⬅️編集画面に遷移できている
      end
      it "editアクションにリクエストするとレスポンスに登録済みuserの名前が存在する" do 
        get edit_user_path(@user)
        expect(response.body).to include @user.nickname
      end
      it "editアクションにリクエストするとレスポンスに登録済みuserのプロフィールが存在する" do 
        get edit_user_path(@user)
        expect(response.body).to include @user.profile
      end
    end

    context 'userがログインしていないとき' do
      it 'editアクションにリクエストすると正常にレスポンスが返ってくる' do
        get edit_user_path(@user)
        expect(response.status).to eq 302  ⬅️トップページにリダイレクトしている
      end
    end
  end
end

これでうまくいきました。
admin_userにしたいときはbefore doで@admin_userを定義して、
sign_in @admin_userとすることで他のコントローラーでも問題なく処理ができました。
テストコードをやるとアプリケーションの仕様がよく理解できると言いますが、理由がよくわかりました。
細かいところに気がついたり、仕様そのものを一から見直す結果になって理解が深まったと実感できました。

参考にさせていただきました

@iwkmsy9618
[Rails]Request Specでのログインの実施

ありがとうございました。

1
0
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
1
0