[Rails]テストコード の書き方

# 背景
テストコードを書くのがとても苦手で嫌いだったのですが、克服するために勉強しました。
その、自分が必死に勉強した内容をまとめて備忘録として記載します。
(一番下にテストコードの記載例あります)

## 手順
※まず単体テストから↓

1.Gemfileに以下を記述する。

```
group :development, :test do
  gem 'rspec-rails', '~> 3.8'
  gem 'factory_bot_rails', '~> 5.0'
end
```

忘れず実行する。

```
$ bundle install
```

 
2.正しくインストールされているか確認する。

```ruby

$ bundle exec rspec --version
# rspecの確認
$ bundle exec gem list | grep factory_bot_rails
# FactoryBotの確認
```

3.RSpecを利用できるようにする。

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

4.テスト用DBを最新の構成にする

```
$ rails db:migrate:reset RAILS_ENV=test
```

5.モデルのテストコードを作成する

```ruby

$ rails generate rspec:model モデル名
# models配下にモデルのテストコードを書くためのファイル(雛型)が生成される
```

6.spec/factoriesのなかの対応するモデルにテストデータを準備する。

```user.rb
FactoryBot.define do

  factory :モデル名 do
    カラム名     {"仮の値"}
  end

end
```

7.spec/models/の中のファイルにテストコードを書く

```user.rb

require 'rails_helper'

RSpec.describe モデル名 do
  describe '#メソッド名' do
    before do
		前提条件
    end
    context 'グループ分けの説明' do
      before do
        このグループの前提条件
      end
      it 'テストの説明' do
		テスト内容
      end
    end
  end
end
```

8.RSpecを実行する

```
$ bundle exec rails test test/models/user.rb
```

9.各モデルの共通メソッドのテストコードのファイルを作成する

```
$ mkdir -p spec/support/concerns/

$ touch spec/support/concerns/common_module.rb

```

10.spec/support/concerns/common_module.rbに共通メソッドのテストコードを書く

```common_module.rb

shared_examples 'テストの説明' do
 ~ 
end
```

11.呼び出し元のモデルに下記記述を追記する。

```user.rb
describe '共通メソッド' do
	it_behaves_like 'テストの説明'
end
```

12.RSpecを実行する

```
$ bundle exec rails test test/models/user.rb
```

13.共通のバリデーションも共通メソッド同様の手順で定義する。

14.コントローラーのテストコードを作成する

```
$ rails generate rspec:integration モデル名
```

15.テストコードを書く

```users.rb
require 'rails_helper'

RSpec.describe "users/index", type: :view do
  describe 'index.html.erbのテスト' do
    it 'h1タグ内にUsersが表示されているかどうか' do
      visit users_path
      expect(page).to have_selector('h1', text: 'Users')
    end
  end
end
```

16.RSpecを実行する
```
$ bundle exec rails test test/requests/users.rb
```

※ここから結合テスト↓

17.Gemfileに以下を追記する。

```
group :test do
  gem 'capybara', '~> 3.28'
  gem 'selenium-webdriver', '~> 3.142'
  gem 'webdrivers', '~> 4.1'
end
```

忘れず実行する。

```
bundle install
```

18.インストールされている確認する

```
bundle exec gem list | grep -e capybara -e selenium-webdriver  -e webdrivers
```

19.spec_helper.rbに以下を追記する。

```spec_helper.rb

require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selenium, using: :chrome, screen_size: [1280, 960]
  end
```

20.結合テストのテストコードのファイルを作成する

```
$ mkdir -p spec/system/

$ touch spec/system/対応するモデル名_spec.rb
```

21.テストコードを書く

22.RSpecを実行する


## テストコード記載例

spec/factories/モデル名.rb

```

FactoryBot.define do

  factory :モデル名 do
    name     {"tanaka"}
    age      {23}
    ...
  end

end
```

spec/models/モデル名.rb

```user.rb
require 'rails_helper'

RSpec.describe モデル名 do
  describe '#メソッド名' do
    before do
		前提条件
    end
    context 'グループ分けの説明' do
      before do
        このグループの前提条件
      end
      it 'テストの説明' do
		テスト内容
      end
    end
  end
end
```


spec/requests/コントローラー名.rb

```users.rb

require 'rails_helper'

RSpec.describe "頭文字が大文字のコントローラー名", type: :request do
  describe "HTTPリクエスト /URL" do
    it "テストの説明(HTTPレスポンスが200になる)" do
      get users_path
      # getリクエストでパス指定
      expect(response).to have_http_status(200)
      # responseに対してhave_http_statusというマッチャで200と等しいかを確認
    end
  end
end
```

spec/upport/concerns/common_module.rb

```common_module.rb
shared_examples '説明' do
  let ~
  context '説明' do
    it '説明' do
      expect(model).not_to be_valid
      expect(model.errors[:name]).to include(I18n.t('errors.messages.blank'))
    end
  end
end

```


system/モデルの複数形.rb

```users.rb
require 'rails_helper'

RSpec.describe モデル名 do
  describe '正常系' do
    before do
		前提条件
    end
    context 'グループ分けの説明' do
      before do
        このグループの前提条件
      end
      it 'テストの説明' do
		テスト内容
      end
    end
  end

　describe '異常系' do
    before do
		前提条件
    end
    context 'グループ分けの説明' do
      before do
        このグループの前提条件
      end
      it 'テストの説明' do
		テスト内容
      end
    end
  end
end
```