Factorybotを使ったテストデータの作成方法

## Factorybotとは
Rspec標準で使える"fixture"に代わり、テストデータの準備をサポートしてくれるライブラリ。
"factory_bot_rails"はRails向けの拡張版のFactorybot

## セットアップ方法
以下をGemfileに追加し、 `bundle install`

```ruby:Gemfile
group :development, :test do
  gem 'factory_bot_rails'
end
```
### ファイル生成
```ruby:
# ジェネレーターコマンドの例
$ bin/rails g factory_bot:model user
```
## サンプルコード
```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user, aliases: [:owner] do
    first_name "Aaron"
    last_name  "Sumner"
    sequence(:email) { |n| "tester#{n}@example.com" }
    password "dottle-nouveau-pavilion-tights-furze"
  end
end

# factoryの名前をモデル名とは別にしたい場合は、以下のようにクラスを指定する
FactoryBot.define do
  factory :admin, class: "User"
  …
```

## ファイルの読み込み先
```ruby:
# デフォルトでは以下のパスのファイルを読み込む
test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb
```

 


## 利用方法
### テストデータの生成
```ruby:xxxx_spec.rb
# 生成と同時に保存しない
user = FactoryBot.build(:user)
user = FactoryBot.build(:user, first_name: nil)
# 生成と同時に保存する
user = FactoryBot.create(:user)
user = FactoryBot.create(:user, first_name: "Joe")
```
### シーケンス
データを生成するたびにn=1,2,3…と割り当てられ、異なるメールアドレスでuserを生成できる。

```ruby:
factory :user do
…
  # シーケンシャルじゃない書き方↓
  # email "tester@example.com"

  # シーケンシャルな書き方↓
  sequence(:email) { |n| "tester#{n}@example.com" }
end
```
### アソシエーション
親子関係にあるクラスで子クラスのデータを生成するときに、親のデータも合わせて生成してくれる。

```ruby:
factory :project do
…
  association :user
  # 先にuserのデータを作って、
  # user_id user.id等の指定がいらない
end
```
### エイリアス
aliasesを指定しておくことで

```ruby:
factory :user, aliases: [:owner] do # "owner"というエイリアスを設定
…
end
```
指定した名前で利用できる。

```ruby:
factory :project do
…
  association :owner # "owner"でuserのファクトリとアソシエーションできている
end
```

### ファクトリをDRYにする
方法１：ファクトリを入れ子状にすることで、継承する。任意の属性だけ書き換えられる。

```ruby:
# ファクトリを継承する
FactoryBot.define do
  factory :project do
    sequence(:name) { |n| "Test Project #{n}" }
    description "Sample project for testing purposes"
    due_on 1.week.from_now
    association :owner

    # 昨日が締め切りのプロジェクト
    factory :project_due_yesterday do
      due_on 1.day.ago
    end
  end
end

# 呼び出し方
project = FactoryBot.create(:project_due_yesterday)
```
方法２：traitをつかう。任意の属性だけ書き換えられる。呼び出し方が少し変わる。

```ruby:
FactoryBot.define do
  factory :project do
    sequence(:name) { |n| "Project #{n}" }
    description "A test project."
    due_on 1.week.from_now
    association :owner

    # 昨日が締め切りのプロジェクト
    trait :due_yesterday do
        due_on 1.day.ago
    end
  end
end

# 呼び出し方
project = FactoryBot.create(:project, :due_yesterday)
```

**使い分け方の例**
私は、インスタンス自体のバリエーションは継承を、インスタンスの状況のバリエーションを表現するときはtraitを使い、生成時の引数に規則性をもたせている

- user、other_user など　→　継承でDRYに
 - FactoryBot.create(:user), FactoryBot.create(:other_user)
- 遅刻したuser、定刻出社のuser　など→　traitでDRYに
 - FactoryBot.create(:user, :late_at_work), FactoryBot.create(:user, :ontime_at_work)

### コールバック
コールバック処理を使って、ファクトリの生成前後に関連処理を実施することができる。以下サンプル。
コールバックを使って関連するデータを作成する必要が あるなら、ファクトリを使うたびに呼び出されないよう、トレイトの中でセットアップすること。詳細は[公式ドキュメント](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#callbacks)を参照。

```ruby:
  # メモ付きのプロジェクト
  trait :with_notes do
    after(:create) { |project| create_list(:note, 5, project: project) }
  end
```





---
## 参考文献
https://github.com/thoughtbot/factory_bot_rails
https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#callbacks