Rspec　結合テストコードの実装手順

初学者の備忘録です！間違い等あればご指摘お願いいたします！

非常に分かりやすい参考記事様 ▶︎https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5

- Ruby2.6.5
- Rails6.0.0

前提
こちらの記事では、Rspecを導入した後の手順を記述しております。

未実装の方はこちらを参考にどうぞ→[Rspecの導入方法](https://qiita.com/yumi1003/items/f222ce82c250e93d1e2f)

# 結合テストコードの準備
結合テストコードは、単体テストコードのように一つ一つの項目のテストだけでなく、ユーザーが辿るであろう一連の流れを確認するためのものです！
単体を一つの流れにくっ付ける、その名の通り**「結合テスト」**ですね！

単体と違う部分は他にもあり、実行コマンドの変化や、**「Capybara」**というGemを使います！
順に見ていきましょう！

### System Spec
System Specは、結合テストコードを記述するための仕組みです。

### Capybara
Capybara（カピバラ）はSystem Specを記述するために必要なGemのことです。
Gemfileを確認すると、すでに搭載されていることが分かります！

*Gemfile*

```
group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  (略)
end 
```

**System Spec(結合テストコードの仕組み)を使うために、CapybaraというGemを使ってく、というイメージです！**
では、早速結合テストコードを書いていきましょう！

# テストコードを記述するファイルの用意
単体テストと同様に、ターミナル上でファイルを生成していきます！
（今回もUserに関するテストコードを記述しますので、記述したいテストにより名前を変えてください！）

*ターミナル*

```
rails g rspec:system users
```

今回の場合、spec/system/users_spec.rbというファイルを作りました！
systemディレクトリ内に入ってるのが結合テストコードってことですね！

# exampleの整理(何をどのような流れでテストするのか？)
単体テストコードでは詳細の記述をしませんでしたが、**テストコードを書く上で一番大事と言っても過言ではない**です。
特に結合テストコードでは一連の流れを考えるわけですからね！
細かく言語化することが重要です。私は実際にユーザーになって動くたびに挙動の記述を繰り返して書いてます！

# テストコードに落とし込み、記述
exampleを書き出したらさっき作ったファイルに書いていきます！（以下は例です）
exampleについては#でコメントアウトします。

*spec/system/users_spec.rb*

```
require 'rails_helper'

RSpec.describe 'ユーザー新規登録', type: :system do
  before do
    @user = FactoryBot.build(:user)
  end
  context 'ユーザー新規登録ができるとき' do 
    it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do
      # トップページに移動する
      # トップページにサインアップページへ遷移するボタンがあることを確認する
      # 新規登録ページへ移動する
      # ユーザー情報を入力する
      # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する
      # トップページへ遷移する
      # カーソルを合わせるとログアウトボタンが表示されることを確認する
      # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する
    end
  end
```

ここにコードの肉付けをしていきます！！
そのために必要なコードの記述方をみていきましょう。

# 新規登録がうまくいくときのテストコード(一例)

### トップページに移動する

### ▶︎visit
visit 〇〇_pathのように記述すると、〇〇のページへ移動する挙動を表現します。
今回はトップということでroot_pathに指定してます。
rails routesで確認し記述しましょう！

```
# トップページに移動する
  visit root_path
```

次にいきましょう！

### トップページにサインアップページへ遷移するボタンがあることを確認する

### ▶︎page
visitで訪れたページの**見える部分**(画面上で見えているもの)の情報が保持されています。
「カーソルを合わせないと確認できない」場合は別メソッド**hover**が必要です。(下記に記述しています)

```
# トップページにサインアップページへ遷移するボタンがあることを確認する
  expect(page).to have_content('新規登録')
```

### 新規登録ページへ移動する
これはトップページに遷移すると同様なので省略します。

### ユーザー情報を入力する

### ▶︎fill_in
fill_in 'フォームの名前', with: '入力する文字列'と記述することで、フォームへの入力を行うことができます。
勝手に書いてくれる優れものです！

**フォームの名前**は検証ツールやhtmlから確認できます。
　※label要素のforに指定されているIDと、inputのidの値が同一になっていることを確認しましょう。
**入力する文字列**に関しては、Fakerなどを活用してみましょう！

```
  visit new_user_registration_path
  # ユーザー情報を入力する
  fill_in 'Nickname', with: @user.nickname
  fill_in 'Email', with: @user.email
  fill_in 'Password', with: @user.password
  fill_in 'Password confirmation', with: @user.password_confirmation
```

さぁどんどん行きましょう！

### サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する

### ▶︎find().click
find('クリックしたい要素').clickと記述することで、実際にクリックができます。
ここでも検証ツールを使ってみましょう！
具体的には、input要素のname属性を指定します。
今回は、
**<input type="submit" name="commit" value="Sign up" data-disable-with="Sign up">**と記述してありました。
この場合、find('input[name="commit"]').clickという記述をすればokです。

サインアップのボタンを押すことは学びましたが、このままでは求めている挙動を満たしてません。

ユーザーモデルのカウントが1上がることの確認をどうするか？
ハイ！マッチャを使ってダブル使いします！

### ▶︎change
expect{ 行う動作 }.to change { モデル名.count }.by(1)と記述することで、モデルのレコードの数がいくつ変動するのかを確認をします。
(1)を（0）にすれば、動作しなかった場合のテストコードにも使えますね！

行う動作に先ほど覚えた**find('クリックしたい要素').click**を入れればok!


```
# サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する
  expect{
    find('input[name="commit"]').click
  }.to change { User.count }.by(1)
```

### トップページへ遷移する
ここで**visit**を使いたくなりますがちょっと待ってください！
確かに移動するという点では同じです。しかし違う点があります！
今回は、新規登録をする→トップページにリダイレクトするという挙動を実現したいんですよね。
なので、今いるページがどこなのかを確認したいです。
そのときに使いたいのが**current_path(現在いるページのパスを自動指定)**です！

```
# トップページへ遷移したことを確認する
  expect(current_path).to eq(root_path)
```

### カーソルを合わせるとログアウトボタンが表示されることを確認する

### ▶︎hover
隠している特定の要素を確認することができます。クラスなどを指定する場合はその親要素の記述も必要になります！

```
expect(
    find('.user_nav').hover
  ).to have_content('ログアウト')
```

### サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する

### ▶︎have_no_content
have_contentの逆です。文字列が存在しないことの確認ができます。


# テストコードを実行する
ここまで記述お疲れ様でした！
最後に以下のコマンドで確認してください。

*ターミナル*

```
% bundle exec rspec spec/system/users_spec.rb
```

パソコン上でババーっと自動的に挙動確認をしてくれるはずです！
問題なく最後まで実行され、ターミナルにもエラー文が出なければ完成です！