すぐ忘れるので、まとめてみた
Rspecを導入する
group :development, :test do
gem "rspec-rails"
end
rails g rspec:install
# 見やすくするため追加
--format documentation
FactoryBotを導入する
group :development, :test do
gem "factory_bot_rails"
end
##Capybaraを導入する
gem 'capybara'
Rspecを実行する
rails_helperの設定
require 'capybara/rspec'
RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :request #Deviseのテスト
config.include FactoryBot::Syntax::Methods #FactoryBotの利用
end
requrest_spec
requestの導入
# コマンドを打たずに、ファイルを手動で作成しても良い
rails g rspec:request user
require 'rails_helper'
RSpec.describe "Tops", type: :request do
describe "GET /index" do
before do
get root_path
end
example "topページへアクセスできること" do
expect(response).to have_http_status(:success)
end
example "ログイン機能が含まれること" do
expect(response.body).to include("ログイン")
end
end
end
Deviseのspec
class UsersController < ApplicationController
before_action :authenticate_user!
def index
@user = User.find(current_user.id)
end
end
FactoryBot.define do
factory :testuser, class: 'User' do
name { "testuser" }
sequence(:email) { |n| "testuser#{n}@user.com" }
password { "foobar" }
end
end
require 'rails_helper'
RSpec.describe "Users", type: :request do
let(:user) { create(:testuser) }
describe "GET /index" do
context "ログインしていない場合" do
example "ログインページへリダイレクトすること" do
get users_path
expect(response).to redirect_to user_session_path
end
end
context "ログインしている場合" do
before do
sign_in user
get users_path
end
example "indexページが表示できること" do
expect(response).to have_http_status(:success)
end
example "ユーザー情報が含まれること" do
expect(response.body).to include(user.name)
expect(response.body).to include(user.email)
end
end
end
ransackのspec
class InstitutionsController < ApplicationController
before_action :set_q
def index
max_num = 50
if @q.result.count > 50
@institution = @q.result.limit(max_num)
else
@institution = @q.result.all
end
end
private
def set_q
@q = Institution.ransack(params[:q])
end
end
<div class="institution_index_main">
<h3>医療機関検索フォーム</h1>
<%= search_form_for @q, url: institutions_path do |f| %>
<div class="flex_center">
<div class="search_form_container">
<div class="addres_cont_container">
<%= f.label :address_cont, '住所で検索' %>
<%= f.search_field :address_cont %>
</div>
<div class="name_introduction_cont_container">
<%= f.label :name_or_introduction_cont, '情報で検索' %>
<%= f.search_field :name_or_introduction_cont %>
</div>
</div>
<div class="search_submit_container">
<%= f.submit '検 索', class:"search_submit", id: "institution_search_submit" %>
</div>
</div>
<% end %>
</div>
FactoryBot.define do
factory :testinstitution, class: "Institution" do
name { "testinstitution" }
postcode { 1234567 }
address { "東京都東京区東京1-2-3東京ビル1F" }
end
end
# request_specの場合
require 'rails_helper'
RSpec.describe "Institutions", type: :request do
let!(:institution) { create(:testinstitution) }
describe "GET /index" do
before do
get institutions_path, params: { q: { name_cont: "test"} }
end
example "ページを表示できること" do
expect(response).to have_http_status(:success)
end
example "医療機関情報が含まれること" do
expect(response.body).to include(institution.name)
expect(response.body).to include(institution.address)
end
end
end
# feature_specの場合
require 'rails_helper'
RSpec.feature "Institution_Features", type: :feature do
let!(:institution) { create(:testinstitution) }
feature "医療機関検索" do
before do
visit institutions_path
end
scenario "住所に検索語を含むとき" do
fill_in 'q[address_cont]', with: '東京都'
find('#institution_search_submit').click
expect(page.status_code).to eq(200)
expect(page).to have_content(institution.name)
expect(page).to have_content(institution.address)
end
scenario "住所に検索語を含まないとき" do
fill_in 'q[address_cont]', with: '大阪府'
find('#institution_search_submit').click
expect(page.status_code).to eq(200)
expect(page).not_to have_content(institution.name)
expect(page).not_to have_content(institution.address)
end
scenario "検索欄が空欄のとき" do
fill_in 'q[address_cont]', with: ''
find('#institution_search_submit').click
expect(page.status_code).to eq(200)
expect(page).to have_content(institution.name)
expect(page).to have_content(institution.address)
end
scenario "名前に検索語を含むとき" do
fill_in 'q[name_or_introduction_cont]', with: 'test'
find('#institution_search_submit').click
expect(page.status_code).to eq(200)
expect(page).to have_content(institution.name)
expect(page).to have_content(institution.address)
end
scenario "名前に検索語を含まないとき" do
fill_in 'q[name_or_introduction_cont]', with: 'example'
find('#institution_search_submit').click
expect(page.status_code).to eq(200)
expect(page).not_to have_content(institution.name)
expect(page).not_to have_content(institution.address)
end
scenario "検索欄が空欄の時" do
fill_in 'q[name_or_introduction_cont]', with: ''
find('#institution_search_submit').click
expect(page.status_code).to eq(200)
expect(page).to have_content(institution.name)
expect(page).to have_content(institution.address)
end
end
end
ストロングパラメータのspec
class UsersController < ApplicationController
before_action :authenticate_user!
def update
@user = User.find(current_user.id)
if @user.update(user_params)
redirect_to edit_user_path(current_user), notice: "プロフィール情報を更新しました"
else
render "edit"
end
end
private
def user_params
params.require(:user).permit(:name, :image)
end
end
require 'rails_helper'
RSpec.describe "Users", type: :request do
let(:user) { create(:testuser) }
describe 'POST #create' do
before do
sign_in user
end
example 'リクエストが成功すること' do
put user_path(user.id), params: { user: { name: "exampleuser", image: "image.png" } }
expect(response.status).to eq 302
end
example 'ユーザー名が更新されること' do
expect do
put user_path(user.id), params: { user: { name: "exampleuser", image: "image.png" } }
end.to change { User.find(user.id).name }.from('testuser').to('exampleuser')
end
end
end
POST PUT DELETEメソッドのspec
require 'rails_helper'
RSpec.describe "Institutions", type: :request do
let!(:institution) { create(:testinstitution) }
let(:param) do
{
institution: {
name: 'examplehospital',
postcode: 9876543,
prefecture: "福岡県",
address_city: "福岡市福岡",
address_street: "4-5-6",
address_building: "福岡ショッピング5F",
address: "福岡県福岡市福岡4-5-6福岡ショッピング5F",
introduction: "整形外科、リハビリテーション科",
image: "examplehospital.png"
}
}
end
describe 'POST /create' do
example 'リクエストが成功すること' do
post institutions_path, params: param
expect(response.status).to eq 302
end
example '医療機関が登録されること' do
expect do
post institutions_path, params: param
end.to change(Institution, :count).by(1)
end
end
describe 'PUT /update' do
example 'リクエストが成功すること' do
put institution_path(institution.id), params: param
expect(response.status).to eq 302
end
example '医療機関情報が更新されること' do
expect do
put institution_path(institution.id), params: param
end.to change { Institution.find(institution.id).name }.from('testinstitution').to('examplehospital')
end
end
describe 'DELETE /destroy' do
it 'リクエストが成功すること' do
delete institution_path(institution.id), params: { id: institution.id }
expect(response.status).to eq 302
end
it '医療機関情報が削除されること' do
expect do
delete institution_path(institution.id), params: { id: institution.id }
end.to change(Institution, :count).by(-1)
end
it '医療機関一覧にリダイレクトすること' do
delete institution_path(institution.id), params: { id: institution.id }
expect(response).to redirect_to(institutions_path)
end
end
end
feature_spec
require 'rails_helper'
RSpec.feature 'Users_Features', type: :feature do
include Devise::Test::IntegrationHelpers
describe "user_login" do
let(:user) { create(:testuser)}
scenario "新規作成できるか" do
visit new_user_registration_path
expect(page).to have_content("新規登録")
fill_in "user_registration_email", with: "example@example.com"
fill_in "user_registration_password", with: "foobar"
fill_in "user_registration_confirm_password", with: "foobar"
expect do
click_button "新規登録"
end.to change(User, :count).by(1)
end
end
describe "link_to_users" do
let(:user) { create(:testuser) }
background do
sign_in user
end
scenario 'プロフィール画面からプロフィール編集画面へ遷移できるか' do
visit users_path
expect(page).to have_content(user.name)
expect(page).to have_content(user.email)
expect(page).to have_content("アカウント情報を編集する")
expect(page).to have_content("プロフィールを編集する")
click_link "プロフィールを編集する"
expect(page).to have_content("ユーザープロフィール編集")
end
end
end
class Consultationhour < ApplicationRecord
belongs_to :institution
validates :start_time, presence: true, format: { with: /[[0-2]0-9]:[0-5][0-9]/, message: "は[00:00]の形式で入力してください" }
validates :end_time, presence: true, format: { with: /[[0-2]0-9]:[0-5][0-9]/, message: "は[00:00]の形式で入力してください" }
validate :before_start_time
def before_start_time
if start_time != nil && end_time != nil
if end_time < start_time
errors.add(:end_time, "は開始時間よりも後に設定してください")
end
end
end
end
require 'rails_helper'
RSpec.feature "Consultationhour_Features", type: :feature do
let(:medicalstaff) { create(:teststaff) }
let(:institution) { create(:testinstitution) }
before do
login_staff(medicalstaff)
end
feature "登録内容が正しいとき" do
before do
visit institution_path(institution.id)
click_link "診療時間を登録する"
end
scenario "新規作成できるか" do
fill_in "new_start_time", with: "08:00"
fill_in "new_end_time", with: "13:00"
find('.monday_container').all('option')[1].select_option
find('.tuesday_container').all('option')[1].select_option
find('.wednesday_container').all('option')[0].select_option
find('.thursday_container').all('option')[1].select_option
find('.friday_container').all('option')[1].select_option
find('.saturday_container').all('option')[1].select_option
find('.sunday_container').all('option')[2].select_option
find('.holiday_container').all('option')[1].select_option
fill_in "new_detail", with: "日曜日は非常勤医師"
expect do
click_button "登録する"
end.to change(Consultationhour, :count).by(1)
expect(page).to have_content("診療時間を追加しました")
expect(page).to have_content("日曜日は非常勤医師")
end
end
feature "登録内容が正しくないとき" do
before do
visit institution_path(institution.id)
click_link "診療時間を登録する"
end
scenario "未入力エラーメッセージが表示されるか" do
click_button "登録する"
expect(page).to have_content("開始時間が入力されていません")
expect(page).to have_content("開始時間は[00:00]の形式で入力してください")
expect(page).to have_content("終了時間が入力されていません")
expect(page).to have_content("終了時間は[00:00]の形式で入力してください")
end
scenario "開始時間と終了時間のエラーメッセージが表示されるか" do
fill_in "new_start_time", with: "13:00"
fill_in "new_end_time", with: "10:00"
click_button "登録する"
expect(page).to have_content("終了時間は開始時間よりも後に設定してください")
end
end
end
中間テーブルのテスト
FactoryBot.define do
factory :testfavorite, class: "Favorite" do
user { create(:testuser) }
institution { create(:institution) }
end
end
describe "link_to_users" do
let!(:user) { create(:testuser) }
let!(:institution) { create(:testinstitution) }
let!(:favorite) { create(:testfavorite, user: user, institution: institution) }
background do
sign_in user
end
scenario 'プロフィール画面からアカウント情報編集画面へ遷移し、プロフィール画面へ戻れるか', js: true do
visit users_path
expect(page).to have_content("お気に入り解除")
find('.like-btn').click
expect(page).not_to have_content("お気に入り解除")
end
別)user作成時にfavoriteを作成する方法
FactoryBot.define do
factory :testuser, class: 'User' do
name { "testuser" }
sequence(:email) { |n| "testuser#{n}@user.com" }
password { "foobar" }
after(:create) do |user|
create(:testfavorite, user: user, institution: create(:testinstitution) )
end
end
end
# traitを使う方法
FactoryBot.define do
factory :testuser, class: 'User' do
name { "testuser" }
sequence(:email) { |n| "testuser#{n}@user.com" }
password { "foobar" }
trait :user_favorite do
after(:create) do |user|
create(:testfavorite, user: user, institution: create(:testinstitution) )
end
end
end
end
let(:user) { create(:testuser, :user_favorite) } # favoriteを作る
let(:user) { create(:testuser) } # favoriteを作らない
Javascriptのリンクをテスト
Capybara.javascript_driver = :selenium_chrome_headless # 追加
FactoryBot.define do
factory :testinstitution, class: "Institution" do
name { "testinstitution" }
postcode { 1234567 }
prefecture { "東京都" }
address_city { "東京区東京" }
address_street { "1-2-3" }
address_building { "東京ビル1F" }
address { "東京都東京区東京1-2-3東京ビル1F" }
end
end
require 'rails_helper'
RSpec.feature "Institution_Features", type: :feature do
let!(:institution) { create(:testinstitution) }
scenario "詳細ページへ遷移できるか", js: true do
visit institutions_path
find(".institution_index_tbody_tr").click
expect(page).to have_content("医療機関情報")
expect(page).to have_content("編 集")
expect(page).to have_content("削 除")
end
scenario "医療機関情報を編集できるか" do
visit edit_institution_path(institution.id)
expect(page).to have_content("医療機関情報修正")
fill_in "institution_name_text", with: "testclinic"
click_button "更新する"
expect(page).to have_content("testclinic")
expect(page).not_to have_content(institution.name)
end
end
ヘルパーを導入する
module LoginMacro
def login_staff(staff)
visit new_medicalstaff_session_path
fill_in 'medicalstaff_login_email', with: staff.email
fill_in 'medicalstaff_login_password', with: staff.password
click_on 'ログイン'
end
end
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
# 有効化
RSpec.configure do |config|
config.include LoginMacro # 追加
config.include Devise::Test::IntegrationHelpers, type: :request
config.include FactoryBot::Syntax::Methods
Capybara.javascript_driver = :selenium_chrome_headless
end
RSpec.feature "Institution_Features", type: :feature do
let!(:institution) { create(:testinstitution) }
feature "medicalstaffでログインしたとき" do
let(:medicalstaff) { create(:teststaff) }
before do
login_staff(medicalstaff)
end
scenario "新規作成画面へ遷移できるか" do
visit institutions_path
expect(page).to have_content("医療機関検索フォーム")
expect(page).to have_content(institution.name)
click_link "新規作成"
expect(page).to have_content("医療機関情報新規作成")
end
end
end
参考資料
Rspecを導入する
RSpecには表示の出力をキレイにする --format documentation というオプションがある
FactoryBotを導入する
【Rails】RSpecとFactroyBotの導入・設定まとめ
FactoryBotを使う時に覚えておきたい、たった5つのこと
RSpec - FactoryBotを導入し、効率良く意味のあるデータを作成する
Capybaraを導入する
Rspecを実行する
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」
Rspecでbindingを使って変数の中身を調べる方法
現場で使えるRSpecパターン集 for Rails App
今日から使える!RSpec 3で追加された8つの新機能
requrest_spec
Rails RSpecの基本 ~Controller編~
Rails5でコントローラのテストをController specからRequest specに移行する
Deviseのspec
[Rails]Request Specでのログインの実施
RSpec初心者のdevise認証システムテスト
Request SpecでDeviseのsing_in userを実施する
ransackのspec
ruby-on-rails - Rspecテストのランサックは常にすべてのインスタンスを返す
【Rails6】RSpecによる検索機能(ransack)の結合テストの実装
ストロングパラメータのspec
Request Specでテストを書くときはStrong Parametersを通る前のパラメーターも意識しましょう
POST PUT DELETEメソッドのspec
Rails5でコントローラのテストをController specからRequest specに移行する
feature_spec
[Rails, devise, RSpec] テストでサインインする
使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」
【RSpec/capybara】fill_inが上手く動作しない
[Rails][RSpec] Capybaraでフォーム入力をシミュレートしてテストする
【Capybara】idもnameもlabelも存在しないセレクトボックスのオプションを選択する
中間テーブルのテスト
rspecのテスト環境で多対多のアソシエーションを一括生成する方法 +α
コントローラー単体テストエラーを解決したいです。
FactoryBotで中間テーブルのテストデータを用意する方法