【Ruby on Rails】コントローラーの単体テストコードについてまとめ(RSpec)

初学者です。
テストコードがなぜか大好きです。

今回はコントローラーの単体テストコードについてまとめます。
私はRSpecを利用しています。

コントローラーのテストコードを書く方針は
アクションにリクエストを送ったとき想定通りのレスポンスが返されるかどうかを確かめる
ことです。

ちなみにモデルの単体テストコードについては[こちら](https://qiita.com/mumucochimu/items/9920699b4a86a8b168af)にまとめています。


## 前提条件

- pry-railsを導入済みである
- FactoryBotを導入済みである
- RSpec導入済みである

上記については以下の記事にまとめています。

[【Ruby on Rails】デバッグツール(pry-rails)](https://qiita.com/mumucochimu/items/7eb477077c493822977c)
[【Ruby on Rails】FactoryBotとFakerについてまとめ](https://qiita.com/mumucochimu/items/10432fd5173e63ebd418)
[【Ruby on Rails】モデルの単体テストコードについてまとめ(RSpec)](https://qiita.com/mumucochimu/items/9920699b4a86a8b168af)

## 準備

下記コマンドでテストコード用のファイルを生成します。
成功すれば`spec/requests`配下に該当のファイルが生成されます。

```Ruby:ターミナル
rails g rspec:request samples
```

## テストコード

`describe`と`it`で検証すべき項目を出していきます。

```Ruby:spec/requests/samples_spec.rb
require 'rails_helper'
describe SamplesController, type: :request do

  before do
    @sample = FactoryBot.create(:sample)
  end

  describe 'GET #index' do
    it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 
    end
    it 'indexアクションにリクエストするとレスポンスに投稿済みのテキストが存在する' do 
    end
    it 'indexアクションにリクエストするとレスポンスに投稿済みの画像URLが存在する' do 
    end
    it 'indexアクションにリクエストするとレスポンスに投稿フォームが存在する' do 
    end
  end
end
```

FactoryBotは`build`ではなく`create`にしています。
今回のテストではDBにデータが存在する必要があるのでcreateです。
テストする度にデータが作られ、終わると削除されます。便利！


では`indexアクションにリクエストすると正常にレスポンスが返ってくる`のテストコードを書いていきます。

```Ruby:spec/requests/samples_spec.rb
it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 

# 以下を追加
  get root_path
  binding.pry

end
```

解説します。
`get ○○_path`でどのパスにリクエストを送りたいかを書きます。
`rails routes`で確認してそのパスを記述します。

この状態で下記コマンドでテストコードを実行します。

```Ruby:ターミナル
bundle exec rspec spec/requests/samples_spec.rb
```

`binding.pry`してるので処理が途中で止まりターミナルに入力できるようになっていると思います。
下記のコマンドを入力します。

```Ruby:ターミナル
response.status
```

そうするとそのレスポンスのステータスコードが出力されます。
HTTP通信においてステータスコードは以下のようになっています。

| ステータスコード | 内容             |
|-------------|------------------|
| 100~        | 処理継続中         |
| 200~        | 処理成功          |
| 300~        | リダイレクト         |
| 400~        | クライアント側のエラー |
| 500~        | サーバーエラー      |

つまり今回の場合は`response.status`で`200`がステータスコードで返ってくればOKということです。

正常に200が返ってきたらテストコードを編集します。

```Ruby:spec/requests/samples_spec.rb
it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do 
  get root_path

# 以下に編集
  expect(response.status).to eq 200

end
```

これでテストコードを実行して成功すればOKです。

次に`indexアクションにリクエストするとレスポンスに投稿済みのテキストが存在する`のテストコードを書いていきます。

```Ruby:spec/requests/samples_spec.rb
it 'indexアクションにリクエストするとレスポンスに投稿済みのテキストが存在する' do 

# 以下を追加
  get root_path
  expect(response.body).to include(@sample.text)

end
```

解説します。
`response.body`と記述して`include`で引数の内容(今回はテキスト)が存在するかを確認してます。`body`でブラウザに表示されるHTMLの情報を抜き出すことができます。

これでテストコードを実行して成功すればOKです。

次に`indexアクションにリクエストするとレスポンスに投稿済みの画像URLが存在する`のテストコードを書いていきます。ほぼ先ほどと同じです。

```Ruby:spec/requests/samples_spec.rb
it 'indexアクションにリクエストするとレスポンスに投稿済みの画像URLが存在する' do 
  get root_path
  expect(response.body).to include(@sample.image)
end
```

これでテストコードを実行して成功すればOKです。


次に`indexアクションにリクエストするとレスポンスに投稿フォームが存在する`のテストコードを書いていきます。
難しく考えずにその文言が存在するかを確認できればOKなので下記のようになります。

```Ruby:spec/requests/samples_spec.rb
it 'indexアクションにリクエストするとレスポンスに投稿フォームが存在する' do 
  get root_path
  expect(response.body).to include('投稿する')
end
```

これでテストコードを実行して成功すればOKです。

他のアクションについてもほぼ書き方は同じです！
コントローラーの単体テストコードは結合テストとかぶる部分もありますよねー。

以上です。