単体テストコード(userモデル)記述の流れ

# はじめに
単体テストコードを実行する流れをまとめる

# 単体テストコード実行流れ
## 1.テストコードを記載するファイルを作成する。
    % rails g rspec:model user
    (Userモデル用のテストファイルを作成できる。)

    「create  spec/models/user_spec.rb」と記載が出れば問題ない。

<補足>
RSpecでモデル、ビュー、コントローラーのテストを行うためには、rails_helper.rbというファイルを読み込む必要があるため、
上記で作成したテストファイルの1行目には<strong>require 'rails_helper'</strong>と記述されている。

## 2.テストコードを記載

    #userモデルの単体テストコードの一例（spec/models/user_spec.rb内）    

    require 'rails_helper'
    
    RSpec.describe User, type: :model do
      before do
        @user = FactoryBot.build(:user)
      end
    
      describe 'ユーザー新規登録' do
        context '新規登録できる場合' do
          it '必要事項を全て過不足なく入力すると登録できる' do
            expect(@user).to be_valid
          end
        end
        context '新規作成できない場合' do
          it 'nicknameが空では登録できない' do
            @user.nickname = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Nickname can't be blank")
          end
    
          it 'emailが空では登録できない' do
            @user.email = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Email can't be blank")
          end
    
          it 'emailが重複すると登録できない' do
            @user.save
            another_user = FactoryBot.build(:user)
            another_user.email = @user.email
            another_user.valid?
            expect(another_user.errors.full_messages).to include('Email has already been taken')
          end
    
          it 'emailで@を含まないと登録できない' do
            @user.email = 'testmail'
            @user.valid?
            expect(@user.errors.full_messages).to include('Email is invalid')
          end
    
          it 'passwordが空では登録できない' do
            @user.password = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Password can't be blank")
          end
    
          it 'passwordが6文字未満では登録できない' do
            @user.password = '00000'
            @user.password_confirmation = '00000'
            @user.valid?
            expect(@user.errors.full_messages).to include('Password is too short (minimum is 6 characters)')
          end
    
          it 'passwordで半角英字のみでは登録できない' do
            @user.password = 'aaaaaa'
            @user.password_confirmation = 'aaaaaa'
            @user.valid?
            expect(@user.errors.full_messages).to include('Password には英字と数字の両方を含めて設定してください')
          end
    
          it 'passwordで半角数字のみでは登録できない' do
            @user.password = '000000'
            @user.password_confirmation = '000000'
            @user.valid?
            expect(@user.errors.full_messages).to include('Password には英字と数字の両方を含めて設定してください')
          end
    
          it '全角文字を含むパスワードでは登録できない' do
            @user.password = 'ａａa １１1'
            @user.password_confirmation = 'ａａa １１1'
            @user.valid?
            expect(@user.errors.full_messages).to include('Password には英字と数字の両方を含めて設定してください')
          end
    
          it 'passwordとpassword_confirmationが一致しないと登録できない' do
            @user.password = 'aaa111'
            @user.password_confirmation = 'bbb111'
            @user.valid?
            expect(@user.errors.full_messages).to include("Password confirmation doesn't match Password")
          end
    
          it 'お名前(全角)は、名字が空では登録できない' do
            @user.lastname = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Lastname can't be blank")
          end
    
          it 'お名前(全角)は、名前が空では登録できない' do
            @user.firstname = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Firstname can't be blank")
          end
    
          it 'お名前(全角)は、名字を全角（漢字・ひらがな・カタカナ）で入力しないと登録できない' do
            @user.lastname = 'ﾔﾏﾀﾞ'
            @user.valid?
            expect(@user.errors.full_messages).to include('Lastname 全角文字を使用してください')
          end
    
          it 'お名前(全角)は、名前を全角（漢字・ひらがな・カタカナ）で入力しないと登録できない' do
            @user.firstname = 'ﾀﾛｳ'
            @user.valid?
            expect(@user.errors.full_messages).to include('Firstname 全角文字を使用してください')
          end
    
          it 'お名前カナ(全角)は、名字が空では登録できない' do
            @user.lastname_kana = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Lastname kana can't be blank")
          end
    
          it 'お名前カナ(全角)は、名前が空では登録できない' do
            @user.firstname_kana = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Firstname kana can't be blank")
          end
    
          it 'お名前カナ(全角)は、名字を全角（カタカナ）で入力しないと登録できない' do
            @user.lastname_kana = 'ﾔﾏﾀﾞ'
            @user.valid?
            expect(@user.errors.full_messages).to include('Lastname kana 全角カタカナのみで入力して下さい')
          end
    
          it 'お名前カナ(全角)は、名前を全角（カタカナ）で入力しないと登録できない' do
            @user.firstname_kana = 'ﾀﾛｳ'
            @user.valid?
            expect(@user.errors.full_messages).to include('Firstname kana 全角カタカナのみで入力して下さい')
          end
    
          it '生年月日が空だと登録できない' do
            @user.birthday = ''
            @user.valid?
            expect(@user.errors.full_messages).to include("Birthday can't be blank")
          end
        end
      end
    end

<br>

<補足>
- be_valid
valid?メソッドでtrueが帰ってくることを期待する
- valid?メソッド
バリデーションのテストを行い、登録可能なときは"true",登録不可の場合は"false"を返す
- errors.full_messagesメソッド
valid?メソッドの返り値が"false"の時に、エラー文をできる
- expect(A).to include(B)
Aの中に、Bが含まれることを期待する構文。（完全一致の場合は、マッチャである「include」→「eq」に変更）

詳細は、別途検索してみよう。


## 3.単体テストコードを記述する上での注意点
### 3-1.テストで使用するuser情報等の登録内容は、FactoryBotやFakerを使ってランダムに作成する。

    # Gemfile内に下記2行を追記（FactoryBotやFaker）追加のため。
    group :development, :test do
      # Call 'byebug' anywhere in the code to stop execution and get a debugger console
      gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
      gem 'rspec-rails'
      gem 'factory_bot_rails' 　⇦ この行を追記する
      gem 'faker'　　　　　　　　　　　　　　　　　　　　　　　　　　　⇦　　この行を追記する
    end

    # Gemをアプリに導入
    % bundle install


「spec」ディレクトリの中に「factories」ディレクトリを作成し、
FactoryBot用のusers.rbのファイルを作成する。
    
    #作成したusers.rb内に下記のように記載する
    FactoryBot.define do
      factory :user do
        nickname   { Faker::Name.initials }
        email      { Faker::Internet.free_email }
        password   { 'a1' + Faker::Internet.password(min_length: 4, mix_case: false) }
        password_confirmation { password }
        lastname   { 'やマ田' }
        firstname  { '太ろウ' }
        lastname_kana  { 'ヤマダ' }
        firstname_kana { 'タロウ' }
        birthday { Faker::Date.between(from: '1930-01-01', to: '2017-12-31') }
      end
    end

    #FactoryBotの:userを呼び出すためには、spec/models/user_spec.rb内にbeforeとbuildメソッドを用いて下記のように記述する。
    RSpec.describe User, type: :model do
          before do
            @user = FactoryBot.build(:user)
          end
    ・・・中略
    end

    ＜注意点＞
    ターミナル上でrails cを用いて仮テストする際に、FactoryBotで値を作成できない（KeyErrorが出る）場合は、
    
    % spring stop　
    （springというGemをストップさせるコマンド）    

    を実行してみると解決するかも。

### 3-2.可読性を上げることを意識する
describe　do〜endやcontext　do〜end、it do〜endを駆使し、他者が見やすいコードを記載するように意識する。

## 4.テストコードの実行
    # userモデルのテストコード実行コマンド
    % bundle exec rspec spec/models/user_spec.rb