Rails 3.2.2 + RSpec 2.9.0 + Factory Gril 3.1.0。
##インストール
gem install factory_girl_rails
GemFile
group :development, :test do
gem 'rspec'
gem 'rspec-rails'
gem 'guard-rails'
gem 'factory_girl_rails'
end
bundle install
##基本的な使い方
spec/factories.rb
FactoryGirl.define do
# 使用する際は:team1を指定する
# シンボルがそのままクラス名ならclassは省略できる
# name、addressがモデルの属性
factory :team1, class: Team do
name :team1.to_s
address '住所'
end
end
spec/models/team_spec.rb
require 'spec_helper'
describe Team do
it 'can save.' do
# :team1はfactories.rbで指定したシンボル
# buildだとDBに反映されない
# createだと反映される
team = FactoryGirl.build(:team1)
team.save.should_not be_false
end
end
##specファイルでFactoryGirlを省略できるよう設定
spec/spec_helper.rb
config.include FactoryGirl::Syntax::Methods
##他の属性に依存した値を作る
factory :hoge do
first_name 'fuga'
last_name 'hige'
full_name '#{first_name}.#{last_name}'
end
##createした後に属性を操作
3.3で記法が変更。詳しくはコメント参照。
factory :member1, class: Member do
name :member1.to_s
after_create do |m, evaluator|
m.name.upcase!
end
end
##連番付きのデータを生成
spec/factories.rb
# 連番付きの名前を生成
sequence :member_names do |n|
"name_#{n}"
end
factory :sequence_members, class: Member do
# {}で囲むと遅延評価
# {}がないと連番付きのデータで更新されないので要注意
name { FactoryGirl.generate(:member_names) }
end
# 10件作る
10.times do
FactoryGirl.create(:sequence_members)
end
属性の上書き
factory :member_base, class: Member do
name :member_base.to_s
end
m = FactoryGirl.build(:member_base, { name: 'hogehogehoge' })
別名を付けられる
factory :member_base, aliases: [:player_base, :manager_base], class: Member do
end
一時的な属性
factory :member_base, aliases: [:player_base, :manager_base], class: Member do
# 一時的な属性を定義
# 以降で参照できる
# また通常の属性と同様に外から上書きもできる
ignore do
upcased true
end
name :member_base.to_s
after_create do |m, evaluator|
# 上で定義した属性を参照
m.name.upcase! if evaluator.upcased
end
end
end
##traits
factory :member_base, class: Member do
name :member_base.to_s
# 値を設定済みの属性に別名を付ける感じ
trait :type_player do
member_type 0
end
trait :type_manager do
member_type 1
end
# buildなどをする際は、
# build(:player_base)でできる
# factoryが入れ子になっているけど指定する際には関係なさげ
factory :player_base, traits: [:type_player]
factory :manager_base, traits: [:type_manager]
end
end
# どちらでも結果は同じ
FactoryGirl.build(:player_base)
FactoryGirl.build(:member_base, :player_base)
同じデータを複数作る
FactoryGirl.build_list(:member_base, 100)
FactoryGirl.create_list(:member_base, 100)
コールバック
3.3から変更あり。コメント参照。
- after_build
- after_create
- after_stub
それぞれbuild、create、build_stubbedされた際に実行される。
factory :member, class: Member do
after_build do |m|
end
after_create do |m, evalator|
end
after_stub {}
end
継承みたいなの
factory :member, class: Member do
name 'hoge'
end
# after_createとかの動きがよくわからない
# 上書きできない?
factory :member_ex, parent: :member do
name 'hogehoge'
end
修正
FactoryGirl.define do
factory :member_base do
name 'hoge'
end
end
FactoryGirl.modify do
factory :member_base do
name 'hogehoge'
end
end
ハッシュで生成したデータを取得
FactoryGirl.attributes_for(:member)
サンプル
スポーツなんかのチームを管理することを想定。
チームの配下にメンバーが複数属する。
# -*- coding: utf-8 -*-
require 'faker/japanese'
FactoryGirl.define do
# メンバテーブルの基本データ
factory :member_base, class: Member do
name { Faker::Japanese::Name.name }
trait :type_player do
member_type 1
end
trait :type_manager do
member_type 2
end
# 選手
factory :player, traits: [:type_player]
# 指導者
factory :manager, traits: [:type_manager]
end
# チームとメンバーの中間テーブル
factory :team_member do
team_id 0
member_id 0
end
# チームの基本データ
factory :team_base, class: Team do
ignore do
member_count 0
end
name {"チーム:#{Faker::Japanese::Name.name}"}
after_create do |team, evaluator|
# 指導者を作成
manager = FactoryGirl.create(:manager)
FactoryGirl.create(:team_member, {team_id: team.id, member_id: manager.id})
# 指定された人数分の選手を作成
if evaluator.member_count > 0
members = FactoryGirl.create_list(:player, evaluator.member_count)
members.each do |player|
FactoryGirl.create(:team_member, {team_id: team.id, member_id: player.id})
end
end
end
end
end
# 使い方
team = FactoryGirl.create(:team_base, member_count: 30)