🔰【初学者用】RSpecでテストコードを書こう！④【結合テストの簡単な実装例】

# はじめに
①🔰【初学者用】RSpecでテストコードを書こう！【概念・準備】

https://qiita.com/hondano_gentuki/items/2003971a4f5a97481930

②🔰【初学者用】RSpecでテストコードを書こう！②【簡単な実装例】

https://qiita.com/hondano_gentuki/items/0a91a595df9c0d76f1cc

③🔰【初学者用】RSpecでテストコードを書こう！③【コントローラーの単体テスト簡単な実装例】

https://qiita.com/hondano_gentuki/items/7f5a36c08b9785022d33

投稿④になります！
今回は結合テストを行います。

# 結合テストはどんなテスト？
結合テストとは、ユーザの一連の操作を再現して行うテストのことです。今まで行ってきた単体テストは、モデルのみ、コントローラーのみのようにそれぞれの機能ごとのテストでしたが、結合テストでは一連の流れをテストします。
例えばユーザーがログインすることをテストするのであれば、トップページのログインボタンをクリック、ログインフォームに情報を入力、ログインするボタンをクリック、トップページにログアウトボタンがあることを確認する。
↑凄い大雑把に書きましたが、このようにユーザーが行う流れを想定してテストするのが結合テストです。
結合テストコードを実行するためには、System Specという技術を使用します。

### System Spec
RSpecの導入が完了していれば使用できる、コントローラーのテストコードを書くために特化した手法のこと。

### Capybara
System Specを記述するためには、`Capybara`というGemを用います。すでにデフォルトのRuby on Railsに搭載されています。

今回はユーザーの新規登録についてテストを行います。

# テストコードの具体的実装
まずはファイルの生成
```rails:ターミナル
rails g rspec:system users
```
テストコードを記述していきます。
```rails:spec/system/users_spec.rb
require 'rails_helper'

RSpec.describe 'ユーザー新規登録', type: :system do
  before do
    @user = FactoryBot.build(:user)
  end

  context 'ユーザー新規登録ができるとき' do 
    it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do
      #トップページに移動する
      visit root_path

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

      # 新規登録ページへ移動する
      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上がることを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { User.count }.by(1)

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

      # カーソルを合わせるとログアウトボタンが表示されることを確認する
      expect(
      find('.user_nav').find('span').hover
      ).to have_content('ログアウト')

      # サインアップページへ遷移するボタンやログインページへ遷移するボタンが表示されていないことを確認する
      expect(page).to have_no_content('新規登録')
      expect(page).to have_no_content('ログイン')
    end
  end

  context 'ユーザー新規登録ができないとき' do
    it '誤った情報ではユーザー新規登録ができずに新規登録ページへ戻ってくる' do
      #トップページに移動する
      visit root_path

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

      # 新規登録ページへ移動する
      visit new_user_registration_path

      # ユーザー情報を入力する
      fill_in 'Nickname', with: ''
      fill_in 'Email', with: ''
      fill_in 'Password', with: ''
      fill_in 'Password confirmation', with: ''

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

      # 新規登録ページへ戻されることを確認する
      expect(current_path).to eq('/users')
    end
  end
end
```

いつも通り１つづつ解説していきます！
### visit_path
`visit 〇〇_path`のように記述すると、〇〇のページへ遷移することを表現できます。

### page
visitで訪れた先のページの見える分だけの情報が格納されています。

### have_content
visitで訪れたpageの中に、文字列があるかどうかを判断するマッチャです。
`expect(page).to have_content('X')`と記述すると、現在のページ内にXがあるか判断します。

### have_no_content
have_contentの真逆

### fill_in
fill_in 'フォームの名前', with: '入力する文字列'のように記述することで、フォームへの入力を行うことができます

### find().click
`find('クリックしたい要素').click`と記述することで、指定の要素をクリックすることができます。

### change
`expect{ 何かしらの動作 }.to change { モデル名.count }.by(1)`と記述することによって、モデルのレコードの数がいくつ変動するのかを確認できます。

例えば送信ボタンをクリックした時であれば`find('input[name="commit"]').click`が入ります。

### current_path
現在いるパスを示します。例えば、`expect(current_path).to eq(root_path)`と記述すれば、今いるページが`root_path`であることを確認できます。

### hover
`find('ブラウザ上の要素').hover`とすると、その要素にカーソルを合わせることができます。hoverしないと表示されないものもありますので、こうした表記があります。


# 終わりに
結合テスト。簡単にですがまとめてみました。
もっとたくさん表記はありますが、流れはつかめたのでは無いでしょうか？
それではまた。