FactoryBot & Fakerの導入 (Rspecでの使い方)

初学者です。備忘録がてらまとめました。

- Ruby2.6.5
- Rails6.0.0

### テストコードを効率的に書きたい！

テストコードが冗長になって読みにくい..そんな時に使えるFactoryBot！
例えばUserのログイン機能をテストしたいとします。

以下が使ってないverです。

```
RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
    it 'nicknameが空では登録できない' do
      user = User.new(nickname: '', email: 'test@example', password: '000000', password_confirmation: '000000')
      user.valid?
      expect(user.errors.full_messages).to include("Nickname can't be blank")
    end
```

次にFactoryBot使用verです。

```
RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
    it 'nicknameが空では登録できない' do
      user = FactoryBot.build(:user)  # Userのインスタンス生成
      user.nickname = ''  # nicknameの値を空にする
      user.valid?
      expect(user.errors.full_messages).to include "Nickname can't be blank"
    end
```

**FactoryBot**とは、インスタンスをまとめるGemのことです。別ファイルに書き込んだものを、書くテストコードで使い回しできるんです。

めっちゃ変わった！というわけではありませんが、目視でわかりますね。使ってないと横に伸びてます。

このコードだけだと、効果がわかりづらいのですが、テストコードはあら有る状況を書いていくもの..
FactoryBotを使わないと、チリも詰まればなんとやらと言いますが、まさしくそれで、可読性も下がってしまいます。

ですので、テストコードを書く際は積極的に使いましょう！

# FactoryBotの導入

Gemの一種ですので、いつもの流れです。
**が、**記述する箇所に注意してください！
Gemfileの**group :development, :test do ~ end**の中です。
Rspecと同じ箇所ですね。

Gemfile

```
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', '~> 4.0.0'
  gem 'factory_bot_rails'  　←ここです
end
```

いつものbundle install!

ターミナル

```
% bundle install
```

# インスタンスをまとめるファイルの作成

FactoryBotを書く、もしくはインスタンスをまとめるファイルを作成します。
※ここではUserモデルのテストコードで進めていきます。

spec/factories **/users.rb**　←これを作ります


## 具体的な書き方

生成したファイル内の記述例がこちらです。
**Fakerを使用したほうが良いパターンもあります。詳しくはこの後に記述しています。**

*spec/factories/users.rb*

```
FactoryBot.define do
  factory :user do
    nickname              {'test'}
    email                 {'test@example'}
    password              {'000000'}
    password_confirmation {password}
  end
end
```

この設定したインスタンスをテスト内で使う場合、 **FactoryBot.build(:user)** と書く必要があります！

さっき上で見たテストコードを使って修正します。

*spec/models/user_spec.rb*

```
RSpec.describe User, type: :model do
  describe 'ユーザー新規登録' do
    it 'nicknameが空では登録できない' do
      user = FactoryBot.build(:user)  # Userのインスタンス生成
      user.nickname = ''  # nicknameの値を空にする
      user.valid?
      expect(user.errors.full_messages).to include "Nickname can't be blank"
    end
```

これをさらに可読化させます。

```
RSpec.describe User, type: :model do
  before do　　　　　　　　　　　　　　　←ここに注目！
    @user = FactoryBot.build(:user)
  end

  describe 'ユーザー新規登録' do
    it 'nicknameが空では登録できない' do
      @user.nickname = ''
      @user.valid?
      expect(@user.errors.full_messages).to include "Nickname can't be blank"
    end
```

**@userとbefore**を活用することで、**user = FactoryBot.build(:user)**を繰り返し書かずに済みます。

ここで **before** と **build** が出てきたので簡単に触れましょう。

### before
それぞれのテストコードを実行する前に、先に実行してくれます。コントローラーでもたまに使ってましたね！
今回はこのbeforeくんのおかげでちゃっちゃと記述できています。とっても効率的！

### build
ActiveRecordのnewメソッドと同じように働きます。
build=組み立てる、築くって意味ですもんね！

テストコードがかけたら、下記のコマンドを実行します。

*ターミナル*

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


# 値をランダム生成するFaker
ここまでは、FactoryBot内の詳細を自分で記述していました。(email=test@example、nickname=testなど)
ですが、もしemailなどのバリデーションで一意性などの設定をしていた場合、このままだとテストが通らなくなってしまいます。

そんな時に使うのが**Faker**です！

## Faker
ランダムな値を生成するGemです。メールアドレス、人名、パスワードなど、さまざまな意図に応じたランダムな値を生成してくれます。

[Fakerの公式GitHub](https://github.com/faker-ruby/faker)
[Qiita・Fakerのチートシート](https://qiita.com/tosite0345/items/1d47961947a6770053af)

# Fakerの導入

こちらもGemfileに記述し、bundle installしましょう！
今回も**group :development, :test do**に書いてくださいね！

*Gemfile*

```
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', '~> 4.0.0'
  gem 'factory_bot_rails'
  gem 'faker'
end
```

# Fakerバージョンに記述を変更してみる

emailだけでもいいのですが、せっかくですから三つともFakerバージョンにしてみましょう！

*spec/factories/users.rb*

```
FactoryBot.define do
  factory :user do
    nickname              {Faker::Name.initials(number: 2)}
    email                 {Faker::Internet.free_email}
    password              {Faker::Internet.password(min_length: 6)}
    password_confirmation {password}
  end
end
```

テストしてみましょう。

*ターミナル*

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

緑色で通れば成功です！
お疲れ様でした！