RSpecにおけるFactoryGirlまとめ


## はじめに
FactoryGirlを使って簡単なモックオブジェクトは作れるが、associationやらtraitやらsequenceやら便利な機能をいちいち調べるのめんどくさいので、今のうちにまとめておく。

## FactoryGirlインストール

```ruby:Gemfile
group :test do
  gem 'rspec-rails'
  gem 'factory_girl_rails'
end
```

version指定しないと最新版がインストールされるので、
version指定する場合は、

```ruby:Gemfile
group :test do
  gem 'rspec-rails'
  gem 'factory_girl_rails', '~> 4.0'
end
```

んで、 `bundle install`して完了

## FactoryGirlのファイル生成
基本的にFactoryGrilをインストールした状態で、モデルを作成するとモデルと一緒にファクトリーも生成される。

```console
$ rails g model User name:string

Running via Spring preloader in process 39201
      invoke  active_record
      create    db/migrate/20170720132710_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
      invoke      factory_girl
      create        spec/factories/users.rb
```

ちなみに、作成されたファクトリーの中身は、こんな感じ。

```spec/factories/user.rb
FactoryGirl.define do
  factory :user do
    name "MyString"
  end
end
```

ここにテストデータを書いていきます。

## FactoryGirlの定義

```spec/factories/user.rb
FactoryGirl.define do
  factory :user do
    name "hoge"
  end
end
```

RSpec実行コマンド

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

RSpec.describe User, type: :model do
  describe "User" do
    context "user.nameが生成されるテスト" do
      it "user.nameがhogeである" do
        user_name = FactoryGirl.create(:user).name
        expect(user_name).to eq "hoge"
      end
    end
  end
end
```

## FactoryGirlの設定

FactoryGirlを生成するときに、

```ruby
FactoryGirl.create(:user)
```

と書きますが、`FactoryGirl`の部分は省略できます。

```spec/rails_helper.rb
RSpec.configure do |config|
  ...
  config.include FactoryGirl::Syntax::Methods
  
  #config.fixture_path = "#{::Rails.root}/spec/fixtures"
  ...
end  
```

と記述すれば、省略できます。またfixtureを使用しないのであればコメントアウトしてしましましょう！

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

RSpec.describe User, type: :model do
  describe "User" do
    context "user.nameが生成されるテスト" do
      it "user.nameがhogeである" do
        user_name = create(:user).name
        expect(user_name).to eq "hoge"
      end
    end
  end
end 
```

## FactoryGirlの呼び出し

### build
buildしたオブジェクトを生成（DB保存なし）

```ruby
FactoryGirl.build(:user)
```

### create
createしたオブジェクトを生成（DB保存する）

```ruby
FactoryGirl.create(:user)
```

### attributes_for
hashを生成する

```ruby
FactoryGirl.attributes_for(:user)
```

## ネストしたFactoryGirl
共通部分は最初のブロック内で記述して、変更したい部分はネストさせて使い分けるやり方もある

```spec/factories/user.rb
FactoryGirl.define do
  factory :user do
    available true
    
    factory :user_for_validation do
      name "hoge"
      ...
    end
    
    factory :user_for_method do
      name "fuga"
      ...
    end
    
  end
end
```

### traitでカラムを変更

traitの機能を使うと、同じ名前で複数のバリエーションを用意することができる。
**特定のカラムだけを変更できる。**
複数カラム変更する場合は、楽だし可読性も上がる

```spec/factories/user.rb
FactoryGirl.define do
  factory :user do
    name "hoge"
    
    trait :age_under_20 do
      age 18
      ...
    end
    
    trait :age_over_20 do
      age 35
      ...
    end
    
  end
end
```

FactoryGirlでオブジェクトを生成するとき、traitを第二引数で指定する

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

RSpec.describe User, type: :model do
  describe "User" do
    context "user.nameが生成されるテスト" do
      it "user.nameがhogeである" do
        user_age = FactoryGirl.create(:user, :age_under_20).age
        expect(user_age).to eq 18
      end
    end
  end
end
```

## FactoryGirlでアソシエーションを定義

アソシエーションのテスト時には、関連を定義する必要がある。

```ruby
# app/models/user.rb
class User < ActiveRecord::Base
  has_many :posts
  ...
end

# app/models/post.rb
class Favorite < ActiveRecord::Base
  belongs_to :user
  ...
end

```

```spec/factories/post.rb
FactoryGirl.define do
  factory :post do
    sequence(:title){ |n| "test_#{n}" }
    association :user
  end
end
```

```spec/factories/user.rb
FactoryGirl.define do
  factory :post do
    title "test"
   
    after(:create) do |user, evaluator|
      create_list(:post, 5, user: user)
    end
  end
end
```

これで、`create(:user)`した時に、has_manyのpostオブジェクトも生成される。。はず。。

## 補足
### sequence
自動採番してくれる
作成した順番でnにインクリメントした番号が入る

### create_list
指定した第二引数の数分だけオブジェクトを作成
第三引数は、belongs_toで紐づいているオブジェクトを指定

### evaluator
ブロック変数のevaluatorは全てのオブジェクトが格納される

### after部分について
trait化することも可能。
検証しきれてません...

## 終わりに
ここら辺を覚えれば、初心者から初級者に繰り上げできると思います。
まずは公式ドキュメント！

殴り書きすぎたので、平日の夜にqiitaアップするもんじゃないな~と思いました。。。

## 参考url
[factory_girl/GETTING_STARTED.md at master · thoughtbot/factory_girl](https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md)
[RailsでFactoryGirlを使ってみるメモ [俺の備忘録]](http://o.inchiki.jp/obbr/159#toc_8)
[いまさら聞けないfactory_girl入門 - Grooves開発ブログ](http://tech.grooves.com/entry/2015/04/28/173025#Using_factories)
[RSpecにおけるFactoryGirlの使い方まとめ - Qiita](http://qiita.com/muran001/items/436fd07eba1db18ed622)
[【解決済み】FactoryGirl の relation の定義の仕方がよくわからない＞＜ - yoshiori.github.io](http://yoshiori.github.io/blog/2013/02/03/factory-girl-relation/)