Ruby on Rails5速習実践ガイド chapter5
5-4 本章で記述するテストの種類(RSpec)
テストの一番外枠に位置しているシステムテスト(System Test)が重要
RSpecとはSystemTestが行われるソフトみたいなもの
systemtestの中ではcapybaraというソフトがまるでウェブアプリケーションを実行しているかのように動き、その動きの中でシステムエラーが無いかなどを見てくれる。
5-7 FactoryBotでテストデータを作成できるように準備する
まずはじめにデータベースを使ってテストをする時にはテスト用のデータがないと話にならない。FactoryBotでテストデータを作成し、そこからテストという流れになっている。ここではFactoryBotでの具体的なデータの書き方を見てみる。テストを実行するために必要な具体的な工程は2つある
1.FactoryBotでデータを作成するためのテンプレートを作成する。
2.SystemSepcの適切なbeforeなどで、FactoryBotのテンプレートを利用してテスト用データベースにテストデータを投入する。
FactoryBot.define do
factory :user do #①
name {'テストユーザー'}
email {'test@example.com'}
password {'password'}
end
end
factoryというメソッドを書きその中にユーザー情報(仮)の値を入れた。これがテスト用のデータになる。
①factory:〇〇 do(今回はuser)この〇〇の部分がこのファクトリーの名前となり呼び出す時に使う名前となる。基本は作ったデータのテーブルに対応するクラス(userテーブルに対応するのはuserクラス)の名前を使う。そうすることによってクラス名もfactoryメソッド名も両方をまとめることができる。
しかしどうしてもクラス名とメソッド名が違う物を用いたい場合は
factory :admin_user, class: User do
上記のようにfactory :ファクトリー名, class:クラス名 doというようにしてもいい
テスト用のTaskデータも作成する
FactoryBot.define do
factory :task do
name {'テストを書く'}
description {'RSpec & Capybara & FactoryBotを準備する'}
user #①
end
end
①上記のuserはtaskとuserを関連付けるためのもの(この作ったタスクはどのユーザーのものなのかをここに書く)
5-8 タスクの一覧表示機能のSystemSpec
上記では
1.FactoryBotでデータを作成するためのテンプレートを作成する。
2.SystemSepcの適切なbeforeなどで、FactoryBotのテンプレートを利用してテスト用データベースにテストデータを投入する。
の1番を行ってきた。次に2番のテストをSystemSpecを用いて行う。今回は
一覧画面に移ったら作成済みのタスクが表示されている
といった動作が正しく動くかテストコードを書いて確認してみる。
まず確認するためには動くようのテストコードを書かなければならない。テストコードは
①ユーザーAを作成しておく(準備)
②作成者がユーザーAであるタスクを作成しておく(準備)
③ユーザーAでブラウザからログインする(準備)
④ユーザーAの作成したタスクの名称が画面上に表示されていることを確認(実行)
この4つの工程をテストコードで書いていく
①ユーザーAを作成しておく(準備)
user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
userという名前のファクトリーを引っ張り出してきてその情報をuser_aとしている.
後ろについているnameやemailを書くことによって内容を変更しユーザーAだけの情報が作られる(なおpasswordなどの変更していない部分はfactoryメソッドを作った時に設定した値になる)
②作成者がユーザーAであるタスクを作成しておく(準備)
FactoryBot.create(:task, name: '最初のタスク', user:user_a)
user:user_aと書くことでこのタスクはuser_aが書いたということになる。
③ユーザーAでブラウザからログインする(準備)
ログインするには
A.ログイン画面にいく
B.メールアドレスを入力する
C.パスワードを入力する
D.「ログインする」ボタンを押す
という動作が必要。
A.ログイン画面にいくにはvisit login_pathという書き方で実行できる(visit URL)
visit login_path
B.メールアドレスを入力する、C.パスワードを入力するにはfill_inメソッドを使う
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
D.「ログインする」ボタンを押すにはclick_buttonメソッドを使う
click_button'ログインする'
③をまとめると
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
このようになる。
④ユーザーAの作成したタスクの名称が画面上に表示されていることを確認(実行)
確認するにはRSpec独自の書き方で
expect(page).to have_content '最初のタスク'
expect(page).to→画面に期待するよ
have_content '最初のタスク'→最初のタスクというコンテンツがあるかどうか
という意味になる
以上の操作を1つのコードにまとめてみる
①②③は準備のためのコードなのでbefore
④は実行のためのコードなのでitを使い記入する
require 'rails_helper'
describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
describe '一覧表示機能' do
before do
user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
FactoryBot.create(:task, name: '最初のタスク', user:user_a)
end
context'ユーザーAがログインしているとき' do
before do
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
end
it'ユーザーAが作成したタスクが表示される' do
expect(page).to have_content '最初のタスク'
end
end
end
end
PSpecの概要
5-10 beforeを利用した共通化
ユーザーAだけでなくユーザーBがログインしているパターンを作る
require 'rails_helper'
describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
describe '一覧表示機能' do
before do
user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
FactoryBot.create(:task, name: '最初のタスク', user:user_a)
end
context'ユーザーAがログインしているとき' do
before do
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
end
it'ユーザーAが作成したタスクが表示される' do
expect(page).to have_no_content '最初のタスク'
end
end
context'ユーザーBがログインしているとき' do
before do
visit login_path
fill_in'メールアドレス', with: 'b@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
end
it'ユーザーAが作成したタスクが表示されない' do
expect(page).to have_no_content '最初のタスク'
end
end
end
end
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
が2つあってわかりにくくなる。なのでこれを1つにまとめる。
require 'rails_helper'
describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
describe '一覧表示機能' do
before do
user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
FactoryBot.create(:task, name: '最初のタスク', user:user_a)
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
end
context'ユーザーAがログインしているとき' do
it'ユーザーAが作成したタスクが表示される' do
expect(page).to have_content '最初のタスク'
end
end
context'ユーザーBがログインしているとき' do
before do
FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
end
it'ユーザーAが作成したタスクが表示されない' do
expect(page).to have_no_content '最初のタスク'
end
end
end
end
ユーザーAがログインしているときは上のitを実行し、ユーザーBがログインしているときは下のitを実行する。
5-11 letを利用した共通化
FactoryBotで作ったデータをletを使って変数みたいに扱うことができる。
require 'rails_helper'
describe 'タスク管理機能',type:system do #一番大枠のdescribeにはtype:systemをつける
describe '一覧表示機能' do
let(:user_a){FactoryBot,create(:user, name:'ユーザーA', email: 'a@example.com')} #ユーザーAを作ったパターン
let(:user_b){FactoryBot,create(:user, name:'ユーザーB', email: 'b@example.com')} #ユーザーBを作ったパターン
before do
FactoryBot.create(:task, name: '最初のタスク', user:user_a)
visit login_path
fill_in'メールアドレス', with: login_user.email #ログインするのがAかBかわからないのでどちらでも行けるようにする
fill_in'パスワード', with: login_user.password #ログインするのがAかBかわからないのでどちらでも行けるようにする
click_button'ログインする'
end
context'ユーザーAがログインしているとき' do
let(:login_user){user_a} #上で定義したユーザーAの情報を引き出す
it'ユーザーAが作成したタスクが表示される' do
expect(page).to have_content '最初のタスク'
end
end
context'ユーザーBがログインしているとき' do
let(:login_user){user_b} #上で定義したユーザーBの情報を引き出す
it'ユーザーAが作成したタスクが表示されない' do
expect(page).to have_no_content '最初のタスク'
end
end
end
end
5-13 shared_exampleを利用する
同じitの結果を様々なdescribeで実行する時にまとめる方法
# it操作をshared_example_forに書く
shared_example_for 'ユーザーAが作成したタスクが表示される' do
it {expect(page).to have_content '最初のタスク'}
end
# it_behaves_likeと書くだけでit操作を一回一回書かなくていいようになる
it_behaves_like 'ユーザーAが作成したタスクが表示される'