FactoryGirlテストデータパターン生成方法



## 呼び出し側で属性指定

呼び出し時にハッシュを渡すとデフォルトの値を上書きしてデータを生成できる

```ruby:spec/factories/users.rb
FactoryGirl.define do
  factory :user do
    name "Isaac Newton"
    role "physicist"
    gender "male"
  end
end
```

```
user = FactoryGirl.create(:user, name: "Max Planck")
user.name
  # "Max Planck"
user.role
  # "physicist"
user.gender
  # "male"
```

## ネストによるfactoryの継承（inheritance）

factoryをネストすると親の属性をすべて引き継いだ上で、子のfactoryで指定した属性を上書きしたデータを生成できる.

```ruby:spec/factories/users.rb
FactoryGirl.define do
  factory :user do
    name "Isaac Newton"
    role "physicist"
    gender "male"

    factory :mathematician do
      role "mathematician"
    end

    factory :woman do
      gender "female"
    end
  end
end
```

```
user = FactoryGirl.create(:user)
user.name
  # "Isaac Newton"
user.role
  # "physicist"
user.gender
  # "male"

mathematician = FactoryGirl.create(:mathematician)
mathematician.name
  # "Isaac Newton"
mathematician.role
  # "mathematician"
mathematician.gender
  # "male"

woman = FactoryGirl.create(:woman)
woman.name
  # "Isaac Newton"
woman.role
  # "physicist"
woman.gender
  # "female"
```


## parentによるfactoryの継承（inheritance）

ネストによるfactoryの継承はparent属性を使って以下のように書くこともできる.

```ruby:spec/factories/users.rb
FactoryGirl.define do
  factory :user do
    name "Isaac Newton"
    role "physicist"
    gender "male"
  end

  factory :mathematician, parent: :user do
    role "mathematician"
  end

  factory :woman, parent: :user do
    gender "female"
  end
end
```

```
user = FactoryGirl.create(:user)
user.name
  # "Isaac Newton"
user.role
  # "physicist"
user.gender
  # "male"

mathematician = FactoryGirl.create(:mathematician)
mathematician.name
  # "Isaac Newton"
mathematician.role
  # "mathematician"
mathematician.gender
  # "male"

woman = FactoryGirl.create(:woman)
woman.name
  # "Isaac Newton"
woman.role
  # "physicist"
woman.gender
  # "female"
```

## trait

継承はデータセットのファクトリ名のラベル(:userなど)が新たに作成されるのに対して、traitでは呼び出し側でtrait名を指定する. より柔軟にパターンを網羅させることができる.

```ruby:spec/factories/users.rb
FactoryGirl.define do
  factory :user do
    name "Isaac Newton"
    role "physicist"
    gender "male"

    trait :mathematician do
      role "mathematician"
    end
    
    trait :professor do
      role "professor"
    end
    
    trait :father do
      role "father"
      gender "male"
    end
    
    trait :mother do
      role "mother"
      gender "female"
    end

    trait :man do
      gender "male"
    end
    
    trait :woman do
      gender "female"
    end
  end
end
```

呼び出し時に第２引数にtrait名を指定するとそのtraitブロックで属性を上書きしたデータが返る.

```
FactoryGirl.create(:user, :mathematician).role
  # "mathematician"

mother = FactoryGirl.create(:user, :mother)
mother.name
  # "Isaac Newton"
mother.role
  # "mother"
mother.gender
  # "female"
```

traitは複数指定でき、後に指定したtraitが前の属性を上書きする
 
```
user = FactoryGirl.create(:user, :father, :woman)
user.name
  # "Isaac Newton"
user.role
  # "father"
user.gender
  # "female"
```

## traitを組み合わせたfactoryを作成

factory定義時にtraits属性で配列を渡せばtraitを組み合わせたfactoryを作成できる.

```ruby:spec/factories/users.rb
FactoryGirl.define do
  factory :user do
    name "Isaac Newton"
    role "physicist"
    gender "male"

    trait :mathematician do
      role "mathematician"
    end
    
    trait :professor do
      role "professor"
    end

    trait :man do
      gender "male"
    end
    
    trait :woman do
      gender "female"
    end
  end

  factory :newton_mathematician, traits: [:mathematician], parent: :user
  factory :newton_professor, traits: [:professor], parent: :user
  factory :newton_woman_professor, traits: [:professor, :woman], parent: :user
end
```

```
user = FactoryGirl.create(:newton_mathematician)
user.name
  # "Isaac Newton"
user.role
  # "mathematician"
user.gender
  # "male"

user = FactoryGirl.create(:newton_woman_professor)
user.name
  # "Isaac Newton"
user.role
  # "professor"
user.gender
  # "female"
```

# Conclusion

各属性のパターンはtraitで用意しそれらを組み合わせて、かつ継承を利用して基本的なデータパターンを網羅し、レアケースや汎用性のないデータは呼び出し側で用意する、といった使い方が有効そう.
なるべくテスト計画上重要なパターンをtraitで作成したい.


# References

* https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md

# Environment

```
% ruby -v
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]

% gem list factory_girl

*** LOCAL GEMS ***

factory_girl (4.4.0)
factory_girl_rails (4.4.1)
```