テストコードを書く

なぜテストコードを書くのか
-
アプリケーションが、想定通り正しく動くのか、確認するため。

Ruby on Railsでは、アプリケーションのテストコードを記述する機能を、RSpecというGemを使うことで便利に実装できる。

1. RSpecを導入する
-
① まず、RSpecのGemを導入する


Gemfile

```
group :development, :test do
　　　　( 　~省略~ )
  gem 'rspec-rails', '~> 4.0.0'
end
```

Gemfileを変更したので、

```
~ frima-app % bundle install
```

② RSpecをアプリ内にインストールする


```
~ frima-app % rails g rspec:install
```
③ .rspecファイルに、記述する
テストコードの結果を、ターミナル上で表示するため。

```.rspec
( ~省略~ )
--format documentation
```

2. FactoryBotを導入する
-

FactoryBot：　
インスタンスをまとめられるGem。　テストのときに毎回記述していた、ユーザー生成の記述などを、他のファイルに一まとめにして、各テストで用いるときに使う。

①Gemfile

```
group :development, :test do
  ( ~省略~ )
  gem 'factory_bot_rails'
end
```

```
% bundle install
```

②テストコードと、FactoryBotの記述をするファイルを、同時に作る

```
% rails g rspec:model user
```

③ FactoryBotで、インスタンスを一まとめに

```spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname              {'furima'}
    email                 {'furima@example'}
    password              {'123456'}
    password_confirmation {password}
  end
end
```

④ FactoryBotの使い方

```spec/models/user_spec.rb
RSpec.describe User, type: :model do
 describe 'ユーザー新規登録' do
   before do
      @user = FactoryBot.build(:user) # Userのインスタンス生成
   end

   context '新規登録できないとき’
    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
　　　　　　end
  end
```

3. ランダムな値を生成するFakerを導入する
-

④のエラー文のように、アプリ内で重複したemailを使えないようにする場合、Fakerを使ったほうが良い。なぜなら、複数のテストを行う際に、FactoryBotで固定のemailで複数回試すため、「すでにemailの重複したインスタンスが存在する」といったような形でエラーが出るかもしれないから。

Gemfile 

```
group :development, :test do
  ( ~省略~ )
  gem 'faker'
end
```

```
% bundle install
```


そして、2-③をFakerを使って表してみると、、、

```spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname              {'furima'}
    email                 {Faker::Internet.free_email}
    password              {Faker::Internet.password(min_length: 6)}
    password_confirmation {password}
  end
end
```

4. テストコードを実行する
-

```
% bundle exec rspec spec/models/user_spec.rb 
```

5.　完成版
-

```spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname              {'furima'}
    email                 {Faker::Internet.free_email}
    password              {Faker::Internet.password(min_length: 6)}
    password_confirmation {password}
  end
end
```

```spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
    before do
      @user = FactoryBot.build(:user)
    end

    context '新規登録できる時' do
      it '全ての値が正しく入力されていれば保存できる' do
        expect(@user).to be_valid
      end
      it 'emailが@を含めば登録できる' do
        @user.email= 'test@test.com'
        expect(@user).to be_valid
      end
      it 'nicknameが10文字以下なら登録できる' do
        @user.nickname='testtestte'
        expect(@user).to be_valid
      end
      it 'passwordとpassword_confirmationが6文字以上であれば登録できる' do
        @user.password='123456'
        @user.password_confirmation='123456'
        expect(@user).to be_valid
      end
      it 'passwordとpassword_confirmationが6文字以上であれば登録できる' do
        @user.password='123456'
        @user.password_confirmation='123456'
        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.email='１２３＠１２３'
        @user.valid?
        expect(@user.errors.full_messages).to include("Email is invalid")
      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='testtest.com'
        @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が5文字以下だと登録できない' do
        @user.password='12345'
        @user.valid?
        expect(@user.errors.full_messages).to include("Password is too short (minimum is 6 characters)")
      end

      it 'passwordとpassword_confirmationが不一致だと登録できない' do
        @user.password='123456'
        @user.password_confirmation='234567'
        @user.valid?
        expect(@user.errors.full_messages).to include("Password confirmation doesn't match Password")
      end
      
    end
  end
end
```