LoginSignup
22
15

More than 3 years have passed since last update.

Rspecでサインインメソッドを共通化して切り出す(devise使わないとき)[system spec][request spec]

Last updated at Posted at 2020-07-05

はじめに

サインイン機能の勉強のために、サインイン機能をdeviseを使わないで自作したところ、テストで大変苦労したので、学んだことを以下に記します。

今回は、system specとrequest specでテストを記載し、多くのところで使いまわせるよう、これらの処理を別ファイルに書き出しました。

実行環境は以下の通りです。

  • Rails 5.2.4.2
  • Rspec 4.0.1
  • capybara 3.33.0

サインイン画面について

emailとパスワードでサインインできるフォームを作っています。画像は参考画像です。
sample.png

基本のサインインメソッド

サインインメソッドをsystem specとrequest specとでそれぞれ表すと下記のようになります。今回は、あるショップに所属しているスタッフを作成し、そのスタッフのメールアドレスとパスワードでサインインをします。

system spec

spec\system\shops_spec.rb
let!(:shop) { FactoryBot.create(:shop) }
let!(:user) { FactoryBot.create(:staff, shop_id: shop.id ) }

before do
  visit login_path
  fill_in "E-mail", with: user.email
  fill_in "Password", with: user.password
  click_button 'LOGIN'
end

request spec

spec\system\shops_spec.rb
let!(:shop) { FactoryBot.create(:shop) }
let!(:user) { FactoryBot.create(:staff, shop_id: shop.id ) }

before do
  session_params = { session: { email: user.email, password: user.password } }
  post "/login", params: session_params
end

共通事項をまとめる(1) shared_context

まずは、letで従業員を定義している2行が、両者で重複していたので、それをshared_contextを用いて、別ファイルに書き出します。

spec\support\contexts\user_setup.rb
RSpec.shared_context "user_setup" do
  let!(:shop) { FactoryBot.create(:shop) }
  let!(:user) { FactoryBot.create(:staff, shop_id: shop.id ) }
end

この時、spec\rails_helper.rb内にある、以下の行のコメントアウトを外し、spec\support内のファイルやディレクトリをすべて読み込めるようにしておきます。

spec\rails_helper.rb
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

こちらの設定で、spec内では以下のように記述することで、ユーザーのセットアップができるようになります。

# 任意のspecファイル内
include_context "user_setup"

共通事項をまとめる(2) module

system specとrequest specの共通処理もそれぞれモジュールにまとめることで、いろいろなところで使いまわすことができます。今回作成したファイルは以下の通りです。

system spec

spec\support\sign_in_module.rb
module SignInModule
  def sign_in_as(user)
    visit login_path
    fill_in "E-mail", with: user.email
    fill_in "Password", with: user.password
    click_button 'LOGIN'
  end
end

なお、この時、ファイル名とモジュール名は一致させる必要があるようです。例えば、SignInModuleなら、sign_in_module.rbというファイル名にする必要があります。

▼参考サイト
https://relishapp.com/rspec/rspec-core/v/3-0/docs/helper-methods/define-helper-methods-in-a-module

request spec

spec\support\login_request_module.rb
module SignInRequestModule
  def sign_in_request_as(user)
    session_params = { session: { email: user.email, password: user.password } }
    post "/login", params: session_params
  end
end

rails_helper.rb への記載

このとき、spec\rails_helper.rbには、以下のように記入します。(明示的に読み込むことを記載しないと、読み込めませんでした…。)

spec\rails_helper.rb
RSpec.configure do |config|
  # 中略
  config.include SignInModule
  config.include SignInRequestModule

end

このあたりもう少しDRYにかけそうなので、方法がわかったら追記したいです。

specファイルでの使い方

上記のように記載することで、specファイルではこちらの方法で、それぞれサインインメソッドを呼び出すことができます。

# 任意のsystem specファイル
include_context "user_setup"
before do
  sign_in_as(user)
end
# 任意のrequest specファイル
include_context "user_setup"
before do
  sign_in_request_as(user)
end

まとめ&参考サイト

devise使わないでログイン機能を実装してやる!と頑張って作り始めたのですが、deviseはいろいろなところで手間を簡略化してくれていることがわかりました。これからはdeviseとうまく付き合っていきたいと思います。
一方で、サインインの仕組みにも詳しくなったので、エンジニアとしてのスキルアップはできたと思います。

今回参考にした情報はこちら。
Define helper methods in a module
Request Specを使おう
What is the proper way to sign in as a user in an rspec request spec, without devise?
rails5 can't access session in ActionDispatch::IntegrationTest

22
15
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
22
15