RailsのAPIテストの書き方


## 準備

Rails を api モードで作成

```shell
$ rails new rails-api --api
$ cd rails-api
$ bundle install
$ rails s
```

http://localhost:3000/ へアクセス

User モデル関連のリソースを scaffold で作成

```shell
$ rails generate scaffold User name:string
```

コンソールでユーザーを作成

```shell
$ rails c

> User.create! name: "山田太郎"
```

http://localhost:3000/users/ にアクセスして、ユーザーが作成されているか確認

Rspec をインストール
Gemfile

```rb
group :test do
  gem 'rspec-rails'
end
```

```shell
$ bundle install
```

```shell
$ rails generate rspec:install
```

テストファイルを作成

```
$ rails g rspec:request users_api
```

json ヘルパーを作成
rspec/support/request_helpers

```
module Requests
  module JsonHelpers
    def json
      JSON.parse(response.body)
    end
  end
end
```

rails_helper
rails_helper.rb

```ruby
・
・
・
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } # コメントを外す
・
・
・
RSpec.configure do |config|
・
・
・
  config.include Requests::JsonHelpers, type: :request # ヘルパーを読み込む
end
```

`Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }`
は、rspec/support 以下のファイルを読み込むための設定です。

factry bot をインストール
Gemfile

```rb
group :test do
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end
```

rails_helper.rb

```ruby
RSpec.configure do |config|
・
・
・
  config.include FactoryBot::Syntax::Methods # 追加
  config.include Requests::JsonHelpers, type: :request
end
```

FactyBot のメソッドを使うための設定を記述
support/factry_bot.rb

```rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
```

user ファイルを作成

```
$ rails g factory_bot:model user
```

factry/user.rb

```rb
FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "TEST_NAME#{n}"}
  end
end
```

## テストを書く

GET の例

```rb
  describe "GET /users" do
    before do
      create_list(:user, 10)
    end
    it 'ユーザー一覧が表示されること' do
      get "/users"
      expect(response.status).to eq(200)
      expect(json.length).to eq(User.count)
    end
  end

  describe "GET /users/1" do
    before do
      @user = create(:user)
    end
    it 'ユーザーの詳細が表示されること' do
      get "/users/#{@user.id}"
      expect(response.status).to eq(200)
      expect(json['name']).to eq(@user.name)
    end
  end
```

POST の例

```rb
  describe "POST /users" do
    before do
      @user_create_params = {
        user: {
          name: "user_name"
        }
      }
    end
    it 'ユーザーが作成されること' do
      expect do
        post "/users", params: @user_create_params
        expect(response.status).to eq(201)
      end.to change {User.count}.by(1)
    end
  end
```

PUT の例

```rb
  describe "PUT /users/1" do
    before do
      @user = create(:user)
      @user_update_params = {
        user: {
          name: "new_user_name"
        }
      }
    end
    it 'ユーザーが更新されること' do
      put "/users/#{@user.id}", params: @user_update_params
      expect(response.status).to eq(200)
      expect(@user.reload.name).to eq(@user_update_params[:user][:name])
    end
  end
```

DELETE の例

```rb
  describe "DELETE /users/1" do
    before do
      @user = create(:user)
    end

    it 'ユーザーが削除されること' do
      expect do
        delete "/users/#{@user.id}"
        expect(response.status).to eq(204)
      end.to change{ User.count }.by(-1)
    end
  end
```

全体

```rb
require 'rails_helper'

RSpec.describe "UsersApis", type: :request do
  describe "GET /users" do
    before do
      create_list(:user, 10)
    end
    it 'ユーザー一覧が表示されること' do
      get "/users"
      expect(response.status).to eq(200)
      expect(json.length).to eq(User.count)
    end
  end

  describe "GET /users/1" do
    before do
      @user = create(:user)
    end
    it 'ユーザーの詳細が表示されること' do
      get "/users/#{@user.id}"
      expect(response.status).to eq(200)
      expect(json['name']).to eq(@user.name)
    end
  end

  describe "POST /users" do
    before do
      @user_create_params = {
        user: {
          name: "user_name"
        }
      }
    end
    it 'ユーザーが作成されること' do
      expect do
        post "/users", params: @user_create_params
        expect(response.status).to eq(201)
      end.to change {User.count}.by(1)
    end
  end

  describe "PUT /users/1" do
    before do
      @user = create(:user)
      @user_update_params = {
        user: {
          name: "new_user_name"
        }
      }
    end
    it 'ユーザーが更新されること' do
      put "/users/#{@user.id}", params: @user_update_params
      expect(response.status).to eq(200)
      expect(@user.reload.name).to eq(@user_update_params[:user][:name])
    end
  end

  describe "DELETE /users/1" do
    before do
      @user = create(:user)
    end

    it 'ユーザーが削除されること' do
      expect do
        delete "/users/#{@user.id}"
        expect(response.status).to eq(204)
      end.to change{ User.count }.by(-1)
    end
  end
end
```