前提条件
- Rails5
- ログイン処理はdeviseを使用
- minitest
ログインしてる時のtestを書きたい
今、userがpostを複数持っているとします
user.rb
class User < ApplicationRecord
has_many :posts, dependent: :delete_all
end
post.rb
class Post < ApplicationRecord
belongs_to :user
end
この時、「新しいpostの新規作成画面」はログインしているユーザーにしか表示したくありません。
posts_controller.rb
class PostsController < ApplicationController
# ログインしてないユーザーを弾く
before_action :authenticate_user!, only: [:new]
def new
@post = Post.new
end
end
ここでtestを普通に書くと
posts_controller_test.rb
require 'test_helper'
class PostsControllerTest < ActionDispatch::IntegrationTest
def setup
@post = posts(:one)
@user = users(:one)
end
def test_new
get new_post_path
assert_response :success
end
end
$ rails test test/controllers/posts_controller_test.rb
...
Expected response to be a <2XX: success>, but was a <302: Found>
ユーザーがログインしてない状態でアクセスしようとしてるので、当然エラーになってしまうんですね。
deviseでログインしてる前提のテストの書き方を調べました。
Devise::TestHelpersはうまくいかない
調べてみると出てくるのがDevise::TestHelpers
をincludeするという方法なのですが、これだとエラーが出てうまくいきません。
posts_controller_test.rb
require 'test_helper'
class PostsControllerTest < ActionDispatch::IntegrationTest
include Devise::TestHelpers #追加
def setup
@post = posts(:one)
@user = users(:one)
end
def test_new
sign_in(@user) #追加
get new_post_path
assert_response :success
end
end
テスト実行すると
$ rails test test/controllers/posts_controller_test.rb
E
Error:
PostsControllerTest#test_new:
NoMethodError: undefined method `env' for nil:NilClass
どうやらこれはPostsControllerTestがActiveSupport::TestCase
を継承してる時に使える方法らしいです。
rails g
で生成される標準のtestのファイルの中だと、modelのtestなどはActiveSupport::TestCase
を継承しているのでこの方法が使えます。
ただ、controllerのtestは標準でActionDispatch::IntegrationTest
を継承しているので、この方法だとエラーが出ているんですね。
Warden::Test::Helpersを使おう!
posts_controller_test.rb
require 'test_helper'
class PostsControllerTest < ActionDispatch::IntegrationTest
include Warden::Test::Helpers #追加
def setup
@post = posts(:one)
@user = users(:one)
end
def test_new
login_as(@user, scope: :user) #追加
get new_post_path
assert_response :success
end
end
ActionDispatch::IntegrationTest
に関してはこの書き方でうまく行くはずです