【Rails/System Spec】結合テストコードの書き方（新規登録に関するテストコード）

## 初めに

今回は結合テストコードの書き方（新規登録に関するテストコード）を実装した記録です。
初めて実装する方でもイメージがしやすいよう、実際の処理画像や考え方の基盤的な部分も合わせてまとめています！

<a href="https://qiita.com/study_matome/items/836691b6242dbdd5dcb9">【Rails/System Spec/Capybara】結合テストコードを書くときによく使う表現 一例</a>もまとめています。


## 結合テストコードとは？
・ユーザーがたどる一連の流れを確認するもの

例　新規登録についての結合テストコード
```
新規登録ボタンの確認　→　新規投稿ページに移動　→ フォームに必要事項入力
　→ 登録ボタンを押す　→ トップページに戻る
```

手動で行うと人的ミスや確認漏れが起こる可能性がありますが、
結合テストコードを実行することで毎回同じ結果が得られるというメリットがあります。

## 結合テストコードを実行するために使うもの

##### ・System Spec(システムスペック)
結合テストコードを記述するための仕組みのこと

##### ・Capybara（カピバラ）
System Specを記述するために必要なGem
こちらはデフォルトでRuby on Railsに搭載されています。（以下Gemfile内）
###### Gemfile
```
group :test do
  gem 'capybara', '>= 2.15' #標準搭載
  gem 'selenium-webdriver'
  gem 'webdrivers'
end
```



## 結合テストコードを書く手順

### ①結合テストコードを書くためのファイルを生成する

今回はユーザー（新規登録）に関する結合テストコードを書いていきます。

```
% rails g rspec:system users
```
生成されたファイル
spec/system/users_spec.rb

---
以下のようなファイル構成になっていれば成功です。
```
 🗂　　spec
 　　∟　　　　🗂 factories
 　　　　　　　　🗂 models
 　　　　　　　　🗂 requests
　　　　　　　　 🗂 system
 　　　　　　　　　　∟ 　users_spec.rb  ←生成されたファイル

```

### ②exampleを整理する

ユーザー目線で考え、「ユーザーがブラウザでどのような操作をすると、どうなるのか」を考えます。

例　ユーザーに関する結合テストコード

・ユーザー新規登録ができるとき
　　正しい情報を入力すればユーザー新規登録ができてトップページに移動する
・ユーザー新規登録ができないとき
　　誤った情報ではユーザー新規登録ができずに新規登録ページへ戻ってくる

この動作を１つ１つ細かく洗い出して、テストコード内に落とし込みます。


----


#### :o:　条件がイメージがしづらい時

実際にアプリで「新規登録」をしてみて、「どのページにいるか」「どのボタンを押すと遷移するか」「どこに何を入力する必要があるか」などを意識して操作すると考えやすくなるのでおすすめです。

----

### ③洗い出した条件を書く
※FactoryBotで新規登録に必要な情報を定義しておきます。

例
```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
  context 'ユーザー新規登録ができないとき' do
    it '誤った情報ではユーザー新規登録ができずに新規登録ページへ戻ってくる' do
      # トップページに移動する
      # トップページに新規登録ページへ遷移するボタンがあることを確認する
      # 新規登録ページへ移動する
      # ユーザー情報を入力する
      # 新規登録ボタンを押してもユーザーモデルのカウントは上がらないことを確認する
      # 新規登録ページへ戻されることを確認する
    end
  end
end
```

中身を書く前に、１度テストコードを実行して正常に動いているか確認します。

```
% bundle exec rspec spec/system/users_spec.rb
```
![スクリーンショット 2022-05-31 14.52.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655769/0436b172-a244-5078-dac2-68fd60d9d5b6.png)

緑色の表示の場合は、テストが正しく通ったことを示しています。
次は中身を書いていきましょう。

---
##### 補足：なぜ中身を書く前に、テストコードを実行するの？
---

理由はエラーの特定がしやすくなるためです。
テストコードは入れ子構造を使っているため、endが抜けるなど文法エラーが出やすい箇所だと感じています。

例　endが足りない場合のエラー
![スクリーンショット 2022-05-31 14.53.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655769/89ebc944-c6b0-4b50-bbfe-88d5c8f95822.png)
 続き　syntax error, unexpected end-of-input, expecting end

---

１度テストコードを実行することで「ここまではエラーはなし」という確認につながるので、
もし以降にエラーが出た場合「この記述以降の箇所でのエラー」であると特定がしやすくなります。


### ④ 実際の結合テストコード

例
```spec/system/users_spec.rb
require 'rails_helper'

def basic_pass(path) #--①説明
  username = ENV['BASIC_AUTH_USER'] 
  password = ENV['BASIC_AUTH_PASSWORD']
  visit "http://#{username}:#{password}@#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}#{path}"
end

RSpec.describe 'ユーザー新規登録', type: :system do
  before do
    @user = FactoryBot.build(:user)
  end
  context 'ユーザー新規登録ができるとき' do 
    it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do
      # トップページに移動する
      basic_pass root_path
      # トップページに新規登録ページへ遷移するボタンがあることを確認する
      expect(page).to have_content('新規登録')
      # 新規登録ページへ移動する
      visit new_user_registration_path
      # ユーザー情報を入力する
      fill_in 'メールアドレス', with: @user.email
      fill_in 'パスワード（英数字6文字以上）', with: @user.password
      fill_in 'パスワード再入力', with: @user.password_confirmation
      fill_in 'ユーザー名（10文字以内）', with: @user.name
      fill_in 'プロフィール', with: @user.profile
      # 新規登録ボタンを押すとユーザーモデルのカウントが1上がることを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { User.count }.by(1)
      # トップページへ遷移したことを確認する
      expect(current_path).to eq(root_path)
      # ログアウトボタンが表示されることを確認する
      expect(page).to have_content('ログアウト')
      # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する
      expect(page).to have_no_content('新規登録')
      expect(page).to have_no_content('ログイン')
    end
  end
  context 'ユーザー新規登録ができないとき' do
    it '誤った情報ではユーザー新規登録ができずに新規登録ページへ戻ってくる' do
      # トップページに移動する
      basic_pass root_path
      # トップページに新規登録ページへ遷移するボタンがあることを確認する
      expect(page).to have_content('新規登録')
      # 新規登録ページへ移動する
      visit new_user_registration_path
      # ユーザー情報を入力する
      fill_in 'メールアドレス', with: ''
      fill_in 'パスワード（英数字6文字以上）',with: ''
      fill_in 'パスワード再入力', with: ''
      fill_in 'ユーザー名（10文字以内）', with: ''
      fill_in 'プロフィール', with: ''
      # 新規登録ボタンを押してもユーザーモデルのカウントは上がらないことを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { User.count }.by(0)
      # 新規登録ページへ戻されることを確認する
      expect(current_path).to eq(user_registration_path)
    end
  end
end

```



--① Basic認証
<a href="https://qiita.com/taka_no_okapi/items/b4cab8e2a451b3f1b88e">Basic認証を交えたテストコードの書き方</a>を参考にさせていただきました。

--補足
上記に出てきた記述については以下で詳しくまとめています。
<a href="https://qiita.com/study_matome/items/836691b6242dbdd5dcb9">【Rails/System Spec/Capybara】結合テストコードを書くときによく使う表現 一例</a>

### ⑤テストコードを実行する

```
% bundle exec rspec spec/system/users_spec.rb
```
![スクリーンショット 2022-05-31 14.52.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655769/0436b172-a244-5078-dac2-68fd60d9d5b6.png)

テストが正しく通ったことを示す緑色の表示の場合は完了です。
お疲れ様でした:exclamation:


## まとめ

最後までご覧くださり ありがとうございました。
今回は結合テストコードの書き方（新規登録に関するテストコード）の記録をまとめました。

初学者のため、記入漏れや記述ミスがありましたら教えていただけると助かります。

こちらの記事がどなたかの参考になれたら幸いです。