Rails チュートリアル（6章）をRSpecでテスト

#はじめに
以前書いた他の章の記事です。
[Rails チュートリアル（３章、４章、５章）をRSpecでテスト](https://qiita.com/sakakinn/items/9c4d6e278cd19867f80f)

追加しました。
[Rails チュートリアル（7章）をRSpecでテスト](https://qiita.com/sakakinn/items/41c0f39152c3713fefc4)
[Rails チュートリアル（8章）をRSpecでテスト](https://qiita.com/sakakinn/items/b54e9181634b34383d98)
#テストの準備

`factory_bot_rails`はテスト用のデータを作成するため、`shoulda-matchers`はバリデーションのテストをするために入れます。（他にも色々なテストで使えるみたいです）

```rb:gemfile

group :development, :test do
  gem 'factory_bot_rails'
  gem 'shoulda-matchers'
end
```
```
$ bundle install
```
###Shoulda-Matchersの設定

```rb:spec/rails_helper.rb

RSpec.configure do |config|
# 省略
end
#--------------追加部分---------------------------
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
#--------------追加部分---------------------------
```

#テストを書く（６章）

###FactoryBotでユーザーの作成

```rb:spec/factories/users.rb

FactoryBot.define do
  factory :user do
    name { 'Example User' }
    sequence(:email) { |n| "user_#{n}@example.com" }
  end
end
```
###Userモデルバリデーションテスト(name, email)

```rb:spec/models/user_spec.rb

require 'rails_helper'

RSpec.describe User, type: :model do

  #facrory botが存在するかのテストです
  it 'has a valid factory bot' do
    expect(build(:user)).to be_valid
  end
  #ここからバリデーションのテストです
  describe 'validations' do
    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to validate_presence_of(:email) }
    it { is_expected.to validate_length_of(:name).is_at_most(50) }
    it { is_expected.to validate_length_of(:email).is_at_most(255) }
    it do
      is_expected.to allow_values('first.last@foo.jp',
                                  'user@example.com',
                                  'USER@foo.COM',
                                  'A_US-ER@foo.bar.org',
                                  'alice+bob@baz.cn').for(:email)
    end
    it do
      is_expected.to_not allow_values('user@example,com',
                                      'user_at_foo.org',
                                      'user.name@example.',
                                      'foo@bar_baz.com',
                                      'foo@bar+baz.com').for(:email)
    end

    describe 'validate unqueness of email' do
      let!(:user) { create(:user, email: 'original@example.com') }
      it 'is invalid with a duplicate email' do
        user = build(:user, email: 'original@example.com')
        expect(user).to_not be_valid
      end
      it 'is case insensitive in email' do
        user = build(:user, email: 'ORIGINAL@EXAMPLE.COM')
        expect(user).to_not be_valid
      end
    end
  end
end
```
ほとんど、`shoulda-matchers`を使って書いてます。
詳しくはここ↓
[thoughtbot/shoulda-matchers -Github](https://github.com/thoughtbot/shoulda-matchers)

emailのユニークのバリデーションだけ`shoulda-matchers`を使ってないです。使うと以下のように書けます。

```rb
it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
```

ただ、使うとundefined method `downcase!' for nil:NilClassとエラーが出てします。
before_saveが読み込めないみたいだけどなんでかな？？？


###Userモデルbefore_saveのテスト（#email_downcase)

```rb:spec/models/user_spec.rb

RSpec.describe User, type: :model do
 
  # 上記省略

  describe 'before_save' do
    describe '#email_downcase' do
      let!(:user) { create(:user, email: 'ORIGINAL@EXAMPLE.COM') }
      it 'makes email to low case' do
        expect(user.reload.email).to eq 'original@example.com'
      end
    end
  end
end
```
ここで`let!`をを使ってます。だと`let`遅延評価され、テスト前にuserがデータベースに登録されず、user.reload.emailの値がnilになってしまいます。
`let!`を使うことでbefore doみたいに先に実行されるみたいです。


# Userモデルのバリデーションテスト（password)

###FactoryBotにパスワードの追加

```rb:spec/factories/users.rb

FactoryBot.define do
  factory :user do
    name { 'Example User' }
    sequence(:email) { |n| "user_#{n}@example.com" }
    password { 'password' }
    password_confirmation { 'password' }
  end
end
```
#Userモデルのテスト（password）


```rb:models/user_spec.rb

require 'rails_helper'

RSpec.describe User, type: :model do
  it 'has a valid factory bot' do
    expect(build(:user)).to be_valid
  end

  # 追加した部分のみ書いてます。
  describe 'validations' do
    describe 'validate presence of password' do
      it 'is invalid with a blank password' do
        user = build(:user, password: ' ' * 6)
        expect(user).to_not be_valid
      end
    end
    it { is_expected.to validate_length_of(:password).is_at_least(6) }
  end
end
```
パスワードの長さと空文字について検証しています。

本当は空文字の検証も`shoulda-matchers`で書こうと思ったのですが、空文字が無視されてしまったので、やめました。

ここまでで、６章おわりです。