開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina
前提
こちらが出来ている前提で進めます。
【Ruby on Rails】RSpec導入まで
※ ▶◯◯ を選択すると、説明等が出てきますので、
よくわからない場合の参考にしていただければと思います。
モデルのテストはこちら
【Ruby on Rails】RSpecでのモデルテスト
コントローラーのテスト準備
##・アクションの作成
今回はユーザーがログインした時だけ、
表示されるかどうかをテストします。
class Admins::PostsController < ApplicationController
before_action :authenticate_user!
def index
@posts = Post.all
end
end
補足【before_action :authenticate_user!】
gem deviseのヘルパーメソッドです。##・ファイルの作成
①
spec配下にrequestsフォルダとfactoriesフォルダを作成。
requestsフォルダには、テストしたいcontrollerのファイルも作成し、
factoriesフォルダにはダミーデータのモデルを作成します。
今回はpostコントローラーをテストするため、
下記のようなファイル構成にします。
spec/requests/posts_request_spec.rb
→テストしたい内容を記述します。
spec/factories/post.rb
spec/factories/admin.rb
→ダミーデータを作成します。
②
FactoryBotを使えるようにします。
使用するとuser = create(:user) のようにDB登録やモデルのビルドができるため便利です。
spec配下にsupportフォルダとfactory_bot.rbファイルを作成し、下記のように記述します。
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
その後、下記を追加します。
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'support/factory_bot' # <ーーー 追加
...
rails_helper.rbの編集
下記内容をRSpec.configure do |config|
内に追加します。
※この記述により、sign_inメソッドが使用できるようになります。
RSpec.configure do |config|
...
config.include Devise::Test::IntegrationHelpers, type: :request # <--追加
end
実際のコード
まずはダミーデータを作成します。
FactoryBot.define do
factory :admin do
email { Faker::Internet.email }
phone_number { 12345678909 }
password { 'password' }
password_confirmation { 'password' }
end
end
FactoryBot.define do
factory :post do
body { Faker::Lorem.characters(number:20) }
admin
end
end
次にテストコードを記述します。
require 'rails_helper'
RSpec.describe "postコントローラーのテスト", type: :request do
let(:admin) { create(:admin) }
let(:post) { create(:post) }
describe 'ログイン済み' do
before do
sign_in admin
end
context "投稿一覧ページが正しく表示される" do
before do
get admins_posts_path
end
it 'リクエストは200 OKとなること' do
expect(response.status).to eq 200
end
it 'タイトルが正しく表示されていること' do
expect(response.body).to include("投稿一覧")
end
end
end
describe '非ログイン' do
context "投稿一覧ページへ遷移されない" do
before do
get admins_posts_path(admin)
end
it 'リクエストは401 OKとなること' do
expect(response.status).to eq 401
end
end
end
# get admins_posts_path(admin)であればパスワードが違うため401エラーであり、
# get admins_posts_pathであれば302のリダイレクトになるため、テストしたい方で記述してください。
# describe '非ログイン' do
# context "投稿一覧ページへ遷移されない" do
# before do
# get admins_posts_path
# end
# it 'リクエストは302 OKとなること' do
# expect(response.status).to eq 302
# end
# end
# end
end
その後、ターミナルで下記を実行してください。
$ rspec spec/requests
テストを通過すると
Finished in 3.64 seconds (files took 2.75 seconds to load)
3 examples, 0 failures
このように表示されるためテスト内容が正しいことを表しています。
参考(モデルのテストから抜粋)
【Ruby on Rails】RSpecでのモデルテスト
逆にテストを通過しない場合、このような形でどこでエラーが起きているかわかるので、
テストコードが間違っているのか、バリデーションが間違っているかなどがわかるようになります。
Failures:
1) Postモデルのテスト バリデーションのテスト titleカラム 20文字以下であること
Failure/Error: let!(:post) { build(:post) }
NoMethodError:
undefined method `build' for #<RSpec::ExampleGroups::Post::Nested::Title:0x000000000619e938>
# ./spec/models/post_spec.rb:9:in `block (3 levels) in <top (required)>'
2) Postモデルのテスト バリデーションのテスト titleカラム 空欄でないこと
Failure/Error: let!(:post) { build(:post) }
NoMethodError:
undefined method `build' for #<RSpec::ExampleGroups::Post::Nested::Title:0x0000000007491518>
# ./spec/models/post_spec.rb:9:in `block (3 levels) in <top (required)>'
Finished in 0.07992 seconds (files took 2.41 seconds to load)
2 examples, 2 failures
Failed examples:
rspec ./spec/models/post_spec.rb:11 # Postモデルのテスト バリデーションのテスト titleカラム 20文字以下であること
rspec ./spec/models/post_spec.rb:15 # Postモデルのテスト バリデーションのテスト titleカラム 空欄でないこと
また下部にあるrspec ./spec/models/post_spec.rb:11を使い、
下記のように個別にテスト内容を確認することも出来ます。
$ rspec spec/models/post_spec.rb:11
まとめ
今回は
1,ログインした状態でpost一覧画面が正しく表示されるか
2,ログインした状態でタイトルが正しく表示されているか
3,非ログインであれば、閲覧することができないか
この3点をテストしました。
フォルダ名のrequestsは
要求したものに対して、正しく応答しているかをテストするため、requestsになっています。
そのため要求するものが違えば、401であったり302のエラーを返すことになるので、
表示させたいエラーによって記述してください。
またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork