Rails学習　2日目その２

#Ruby on Rails5速習実践ガイド chapter5

## 5-4　本章で記述するテストの種類（RSpec)
テストの一番外枠に位置しているシステムテスト(System Test)が重要
RSpecとはSystemTestが行われるソフトみたいなもの
systemtestの中ではcapybaraというソフトがまるでウェブアプリケーションを実行しているかのように動き、その動きの中でシステムエラーが無いかなどを見てくれる。

##5-7 FactoryBotでテストデータを作成できるように準備する
まずはじめにデータベースを使ってテストをする時にはテスト用のデータがないと話にならない。FactoryBotでテストデータを作成し、そこからテストという流れになっている。ここではFactoryBotでの具体的なデータの書き方を見てみる。テストを実行するために必要な具体的な工程は２つある
1.FactoryBotでデータを作成するためのテンプレートを作成する。
2.SystemSepcの適切なbeforeなどで、FactoryBotのテンプレートを利用してテスト用データベースにテストデータを投入する。

 ```ruby:spec/factories/users.rb
FactoryBot.define do
 factory :user do　#①
  name {'テストユーザー'}
  email {'test@example.com'}
  password {'password'}
 end
end
```
factoryというメソッドを書きその中にユーザー情報（仮）の値を入れた。これがテスト用のデータになる。
①factory:〇〇 do（今回はuser）この〇〇の部分がこのファクトリーの名前となり呼び出す時に使う名前となる。基本は作ったデータのテーブルに対応するクラス（userテーブルに対応するのはuserクラス）の名前を使う。そうすることによってクラス名もfactoryメソッド名も両方をまとめることができる。
しかしどうしてもクラス名とメソッド名が違う物を用いたい場合は

```ruby
factory :admin_user, class: User do
```
上記のようにfactory :ファクトリー名, class:クラス名 doというようにしてもいい

テスト用のTaskデータも作成する

```ruby:spec/factories/tasks.rb
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のテンプレートを利用してテスト用データベースにテストデータを投入する。
の１番を行ってきた。次に２番のテストをSystemSpecを用いて行う。今回は
>一覧画面に移ったら作成済みのタスクが表示されている

といった動作が正しく動くかテストコードを書いて確認してみる。
まず確認するためには動くようのテストコードを書かなければならない。テストコードは
>①ユーザーAを作成しておく(準備)
②作成者がユーザーAであるタスクを作成しておく(準備)
③ユーザーAでブラウザからログインする(準備)
④ユーザーAの作成したタスクの名称が画面上に表示されていることを確認(実行)

この４つの工程をテストコードで書いていく

>①ユーザーAを作成しておく（準備）

```ruby:spec/system/tasks_spec.rb
user_a = FactoryBot.create(:user, name: 'ユーザー名', email:'a@example.com')
```
userという名前のファクトリーを引っ張り出してきてその情報をuser_aとしている.
後ろについているnameやemailを書くことによって内容を変更しユーザーAだけの情報が作られる（なおpasswordなどの変更していない部分はfactoryメソッドを作った時に設定した値になる）



>②作成者がユーザーAであるタスクを作成しておく（準備）

```ruby:spec/system/tasks_spec.rb
FactoryBot.create(:task, name: '最初のタスク', user:user_a)
```
user:user_aと書くことでこのタスクはuser_aが書いたということになる。

③ユーザーAでブラウザからログインする（準備）
ログインするには
>A.ログイン画面にいく
B.メールアドレスを入力する
C.パスワードを入力する
D.「ログインする」ボタンを押す

という動作が必要。

A.ログイン画面にいくにはvisit login_pathという書き方で実行できる（visit URL）

```ruby:spec/system/tasks_spec.rb
visit login_path
```

B.メールアドレスを入力する、C.パスワードを入力するにはfill_inメソッドを使う

```ruby:spec/system/tasks_spec.rb
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
```

D.「ログインする」ボタンを押すにはclick_buttonメソッドを使う

```ruby:spec/system/tasks_spec.rb
click_button'ログインする'
```

>③をまとめると

```ruby:spec/system/tasks_spec.rb
visit login_path
fill_in'メールアドレス', with: 'a@example.com'
fill_in'パスワード', with: 'password'
click_button'ログインする'
```
このようになる。

>④ユーザーAの作成したタスクの名称が画面上に表示されていることを確認（実行）

確認するにはRSpec独自の書き方で

```ruby
expect(page).to have_content '最初のタスク'
```

expect(page).to→画面に期待するよ
have_content '最初のタスク'→最初のタスクというコンテンツがあるかどうか
という意味になる

以上の操作を１つのコードにまとめてみる
①②③は準備のためのコードなのでbefore
④は実行のためのコードなのでitを使い記入する

```ruby:spec/system/tasks_spec.rb
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の概要


![Untitled-1 copy.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/815476/c5a1218a-f70b-219e-b6a3-a246211853b2.jpeg)


##5-10　beforeを利用した共通化
ユーザーAだけでなくユーザーBがログインしているパターンを作る

```ruby:spec/system/tasks_spec.rb
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'ログインする'
が２つあってわかりにくくなる。なのでこれを１つにまとめる。

```ruby:spec/system/tasks_spec.rb
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を使って変数みたいに扱うことができる。

```ruby:spec/system/tasks_spec.rb
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で実行する時にまとめる方法

```ruby
#it操作をshared_example_forに書く
shared_example_for 'ユーザーAが作成したタスクが表示される' do
   it {expect(page).to have_content '最初のタスク'}
end

#it_behaves_likeと書くだけでit操作を一回一回書かなくていいようになる
it_behaves_like 'ユーザーAが作成したタスクが表示される'
```