[RSpec]request specでcontrollerテストをやってみる

RSpecのcontorollerテストとして、request specを使ってテストを実行していきます。

#開発環境

> ruby 2.6.3
> Rails 5.2.6

#前提

- FactoryBot使用
- Faker使用
- capybara使用
- devise使用

RSpecの準備、FactoryBotでのテストデータの定義等は、下記記事にまとめてますので、まだの方は先にこちらをどうぞ。
[[Rails]RSpecでテストを行う準備(FactoryBot使用)](https://qiita.com/nakachan1994/items/29369470d50d0fcd0f6c)

#request specとは

おもに、contorollerのテストで、URLのリクエストがちゃんと通るのかテストを実施していきます。

#ファイルの作成

まずは、spec配下に各コントローラーのファイルを作っていきます。

今回は、
posts_spec.rb
contacts_spec.rb
を作っていきます。

作成した各モデルのファイルで、rails_helperの設定を読み込んでいきます。

rails_helperはRSpecの設定が記述してあるファイルです。

コードを１行書くだけで、読み込めるので先に記述しておきます。
最初にまとめて書いておくことで、書き忘れを防げます！

```rb:コントローラーファイル
require 'rails_helper'
```

#deviseのヘルパーを使えるようにする

controllerのテストを実行していく中で、sign_inなどのdeviseのヘルパーを使う機会が出てきます。

なぜRSpecのコードを書いていくときに、deviseのヘルパーが必要かというと、`アクセス権限でログインしてないユーザーを許可していない場合があるから`です。
ユーザーの編集ページはログインしてないときは、アクセスできないなど

`spec/rails_helper.rb`にdeviseのヘルパーを使えるようにコードを追加します。

```spec/rails_helper.rb
:
  # deviseのヘルパーメソッドをrequestsで使用できるように設定
  config.include Devise::Test::IntegrationHelpers, type: :request
end
```

これでdeviseのヘルパーをrequestsで使用できるようになりました。

#テストコードを書いていく

各コントローラーごとにテストコードを書いていきます。

今回テストするコントローラーの各アクションは、以下の通りです。

|controller|action|
|:-:|:-:|
|posts| new, index, show|
|contacts|new,confirm,complete|

基本形はこうです。

```rb:
it "returns http success" do
  # アクセス制限しているところなら
  sign_in
  # URLリクエストを通す
  HTTPメソッド　パス名
  # リクエストが通ったか確認
  expect(response).to have_http_status(:success)
end
```

####posts controller

posts controllerのnewとshowアクションでは、ログインしていないユーザーはアクセスできないようにしてあるので、sign_inヘルパーを使用します。

```spec/requests/posts_spec.rb
require 'rails_helper'

RSpec.describe "Posts", type: :request do
  # FactoryBotのテストデータを使ってuserとpostのデータを作成
  let!(:user) { create(:user) }
  let!(:post) { create(:post, user_id: user.id) }

  describe "GET /new" do
    it "returns http success" do
      sign_in user
      get new_post_path
      expect(response).to have_http_status(:success)
    end
  end

  describe "GET /index" do
    it "returns http success" do
      get posts_path
      expect(response).to have_http_status(:success)
    end
  end

  describe "GET /show" do
    it "returns http success" do
      sign_in user
      get post_path(post)
      expect(response).to have_http_status(:success)
    end
  end
end
```

####contacts controller

contacts controllerでは、アクセス制限をしていないので、sign_inヘルパーは使いません。

confirmアクションがnewアクションからformで値を受け取る形なので、HTTPメソッドがPOSTになってます。

```spec/requests/contacts_spec.rb
require 'rails_helper'

RSpec.describe "Contacts", type: :request do
  describe "GET /new" do
    it "returns http success" do
      get "/contacts/new"
      expect(response).to have_http_status(:success)
    end
  end
  
  # POSTになっている
  describe "POST /confirm" do
    it "returns http success" do
      # newアクションから送られてきた値をもたせてあげる
      post confirm_contacts_path, params: { contact: { name: 'test', email: 'a@a', content: 'content sample' } }
      expect(response).to have_http_status(:success)
    end
  end

  describe "GET /complete" do
    it "returns http success" do
      get "/contacts/complete"
      expect(response).to have_http_status(:success)
    end
  end
end
```

confirm以外は基本形の書き方で問題ないです。

#テストを実行

requests specのテストを実行します。

```
$ bundle exec rspec spec/requests
```

ターミナル結果に`6 examples, 0 failures`があれば、テスト成功です。

#まとめ

URLのリクエストが通るかは重要なテスト項目になりますので、参考にしてテストコードを書いてみてください。

他にもRSpecに関する記事書いてますので、よかったらどうぞ！
[[Rails]RSpecでテストを行う準備(FactoryBot使用)](https://qiita.com/nakachan1994/items/29369470d50d0fcd0f6c)
[[Rails]RSpecでモデルのテスト(FactoryBot使用)](https://qiita.com/nakachan1994/items/d869db15f8482ba70d02)
[[Rails]RSpecでよく使うマッチャー10選](https://qiita.com/nakachan1994/items/e9938d70b3f6345368b2)