【Rails】RSpecテストのコード解説

## RSpecテストとは
Railsでよくつかわれるテストツール。
「人間が読んでも分かりやすいコードでテストを書くこと」を目的としている。
Gemをインストールして、簡単にテストできる。

## describe
これから○○のテストを始めるよと、テストのタイトル的な感じ。
```Ruby
describe 'ログインのテスト' do
end
describe '新規登録のテスト' do
end

describe '商品管理機能のテスト' do
end
```

## context
describeをパターン分けをして、状況ごとにテストの流れを整理する。
ログインのテストなら、成功・失敗などパターンが発生するので、下記のように分岐させる。
```Ruby
describe 'ログインのテスト' do
    context 'ログイン成功した場合のテスト' do
    end
    context 'ログイン失敗した場合のテスト' do
    end
end

describe '商品管理機能のテスト' do
    context '商品が正しく登録される場合のテスト' do
    end
    context '商品登録が失敗する場合のテスト' do
    end
end
```

## it
パターン分けした後に、どのような状態になってることを確認したいのか、具体的に。
```Ruby
describe 'ログインのテスト' do
    context 'ログイン成功した場合のテスト' do
        it 'ログイン後のリダイレクト先が正しいか' do
        end
    end
    context 'ログイン失敗した場合のテスト' do
        it 'ログイン失敗後のリダイレクト先が正しいか' do
        end
    end
end

describe '商品管理機能のテスト' do
    context '商品が正しく登録される場合のテスト' do
        it '保存された商品の情報が正しいか' do
        end
    end
    context '商品登録が失敗する場合のテスト' do
        it 'エラーメッセージが正しいか' do
        end
    end
end
```

## expect( ).to と eq
`expect( ).to`は、( )内を期待値とする。
`eq`は、その期待とeqの後に続く値が同じかを確認。

`expect( ).to` を `エクスペクテーション`、
`eq` を `マッチャー`と呼ぶ。

下記は、「ログイン後、example.com/users/1にリダイレクトする」ようチェックしてる

`current_path`：
現在のページのパスを取得する。

`.to eq`：
その後の値と等しいか確認。この場合「current_path」と等しいか。

`'/users/' + user.id.to_s`：
ユーザIDをto_sで文字列にし、それをusersと結合する。
例えば、user.id が 1 の場合、「/users/1」とする。

```Ruby
describe 'ログインのテスト' do
    context 'ログイン成功した場合のテスト' do
        it 'ログイン後のリダイレクト先が正しいか' do
            expect(current_path).to eq '/users/' + user.id.to_s
        end
    end
end

describe '商品管理機能のテスト' do
  context '商品が正しく登録される場合のテスト' do
    it '保存された商品の情報が正しいか' do
      product = Product.create(name: 'サンプル商品', price: 1000)

      # 商品の名前と価格が正しいかを確認
      expect(product.name).to eq('サンプル商品')
      expect(product.price).to eq(1000)
    end
  end

  context '商品登録が失敗する場合のテスト' do
    it 'エラーメッセージが正しいか' do
      # 商品名が空の場合
      product = Product.create(name: '', price: 1000)

      # 商品名が空だとエラーメッセージが表示されることを確認
      expect(product.errors[:name]).to eq(["can't be blank"])
    end
  end
end
```
他にもよく使われるマッチャー：  
- `be`: 
オブジェクトが同一であるかを確認（例: `expect(obj1).to be obj2`）。  
- `include`: 
配列やハッシュに特定の要素が含まれているかを確認（例: `expect(array).to include value`）。  
- `match`: 
正規表現に一致するかを確認（例: `expect(string).to match /pattern/`）。  

## before
「フック」と呼ぶ。
個々のテストを実行する前に、まとめて共通する部分の前処理をする。
例えば、以下のようなログインのテストの場合、ログインするためのメールアドレスや名前が必要になる。
beforeを使うと、テストの度毎回書く必要がなく、まとめて書くことができる。

- **`fill_in 'user[name]', with: user.name`**
   - 「名前」入力欄に、`user.name`（テスト用のユーザーの名前）を入力させる。
   
- **`fill_in 'user[password]', with: user.password`**
   - 「パスワード」入力欄に、`user.password`（テスト用のユーザーのパスワード）を入力させる。

- **`click_button 'Log in'`**
   - 「ログイン」ボタンをクリックさせる。

**beforeを使わないと…**
``` Ruby
# beforeを使わなかった場合
describe 'ログインのテスト' do
  context 'ログイン成功した場合のテスト' do
    it 'ログイン後のリダイレクト先が正しいか' do
      # ログイン処理を毎回書く必要がある
      fill_in 'user[name]', with: user.name
      fill_in 'user[password]', with: user.password
      click_button 'Log in'
      
      expect(current_path).to eq '/users/' + user.id.to_s
    end

    it 'ログイン後にユーザー名が表示されるか' do
      # ここでも同じ処理を繰り返し書かないといけない
      fill_in 'user[name]', with: user.name
      fill_in 'user[password]', with: user.password
      click_button 'Log in'

      expect(page).to have_content user.name
    end
  end
end
```

**beforeを使うと…**
``` Ruby
# beforeを使った場合
describe 'ログインのテスト' do
  context 'ログイン成功した場合のテスト' do
    # ここにまとめて書ける！コードが簡潔！
    before do
      fill_in 'user[name]', with: user.name
      fill_in 'user[password]', with: user.password
      click_button 'Log in'
    end

    it 'ログイン後のリダイレクト先が正しいか' do
      expect(current_path).to eq '/users/' + user.id.to_s
    end

    it 'ログイン後にユーザー名が表示されるか' do
      expect(page).to have_content user.name
    end
  end
end
```