[Rails] Rspecでテストコードの実装④

# はじめに
テストコードの実装③をみていない方は[こちら](https://qiita.com/tochisuke221/items/1825806dc16c9bdf7716)からご覧ください。

#結合テスト
結合テストとは、ユーザの一連の操作を再現して行うテストのことです。今まで行ってきた単体テストは、機能ごとでしたが、結合テストでは一連の流れを一気に行います（例：投稿機能であれば、ログイン→入力→投稿→表示の確認）。結合テストコードを実行するためには、System Specという技術を使用します。

###System Spec(参考)
System Specを記述するためには、Capybara（カピバラ）というGemを用います。これはすでにデフォルトでRuby on Railsに搭載されています。

```Gemfile
group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end
```

#テストコードの具体的な実装

まずはいいつものようにファイルを生成していきましょう

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

生成されたファイルに以下を記述していきます

```system/users_spec.rb
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
  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
```

一個づつ見ていきましょう。

###visit 〇〇_path
〇〇のページへ遷移することを実現します。前回にやったgetと似ていますが、getは単にリクエストを送るのみです

###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と記述することで、指定の要素をクリックができます。
ちなみに、click_on "文字列"としても同じ効果を得られますが、同じ文字列が2つ以上あると使えません

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

###current_path
現在いるパスを示します

###hover
find('ブラウザ上の要素').hoverとすると、その要素にカーソルを合わせることが可能です。hoverしないと表示されないものもありますので、こうした表記があります。
<br>
以上のマッチャ等をしっかり理解した上で、再度テストコードを見てみるとその意味はかなりわかりやすくなるのではないでしょうか
解説をコメントアウトにいれてありますのでご覧ください。


```system/users_spec.rb
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
```

#（参考）その他よく使う表記まとめ

###have_selector
指定したセレクタが存在するかどうかを判断するマッチャ。have_selector ".クラス名または#id名"という形で記述できます。

###have_link

expect('要素').to have_link 'ボタンの文字列', href: 'リンク先のパス'と記述することで、要素の中に当てはまるリンクがあることを確認する。
なお、have_content同様に、have_no_linkもある

###all
all('クラス名')でpageに存在する同名のクラスを持つ要素をまとめて取得できます。all('クラス名')[0]のように添字を加えることで指定版目のものを取得できます

###find_link().click
個人的にはあまり使いませんが、、、a要素で表示されているリンクをクリックするために用います。find().clickと似ていますが、find_link().clickはa要素のみに対して用いることができます。



#おわりに
お疲れ様でした。
今回は結合テストについて、簡単にまとめてみました。他にもいろいろなパターンがあるかと思いますので、ぜひ考えてみてください！！