FactoryBot はフィクスチャのツールです。
多くのフィクスチャを必要とするときは Traits が便利です。
Setup
Ruby on Rails に RSpec のテスト環境を構築して確認しましょう。
今回はコンソールモードで確認します。spec/factories
のファイルを修正するとコンソールで FactoryBot.reload
を実行してください。
mkdir factory_bot_rails_example && cd factory_bot_rails_example/ && rails new . --api -BT
echo "gem 'pry-rails', group: [:development]" >> Gemfile
echo "gem 'factory_bot_rails', group: [:development, :test]" >> Gemfile
echo "gem 'rspec-rails', group: [:development, :test]" >> Gemfile
bundle
bundle exec rails generate rspec:install
rails generate model product title vendor state
rails console
Usage
Trait
trait
は項目をグループにすることができます。
FactoryBot.define do
factory :product do
title 'iPad'
trait :modify do
title 'iPhone'
end
end
end
フィクスチャにするにはトレイトのシンボルを第2引数に指定します。
例では、シンボルにmodify
を指定するとtitle
がiPad
からiPhone
に変更されます。
[1] pry(main)> FactoryBot.reload
[2] pry(main)> FactoryBot.attributes_for(:product)
=> {
:title => "iPad"
}
[3] pry(main)> FactoryBot.attributes_for(:product, :modify)
=> {
:title => "iPhone"
}
Traits
traits
でtrait
をまとめることができます。
trait :base do
vendor 'Apple'
end
trait :activate do
state :active
end
factory :product_activate, traits: [:base, :activate]
トレイトのシンボルをは引数に複数を指定できます。また、traits
は第1引数にシンボルを指定します。
例では、同じ値が出力されています。フィクスチャにラベルが付いて便利ですね。
[4] pry(main)> FactoryBot.reload
[5] pry(main)> FactoryBot.attributes_for(:product, :base, :activate)
=> {
:title => "iPad",
:vendor => "Apple",
:state => :active
}
[6] pry(main)> FactoryBot.attributes_for(:product, :base, :activate)
=> {
:title => "iPad",
:vendor => "Apple",
:state => :active
}
Transient
transient
は内部で利用する変数ですが、trait
と組合せて利用することができます。
transient do
time true
end
trait :cancel do
state :canceled
canceled_at { Time.now if time }
end
factory :product_cancel, traits: [:base, :cancel]
trait
のブロッブのブロックはある程度は自由なエリアです。 (夢が広がりますね。
例では、time
変数でcanceled_at
のセットを制御しました。
[7] pry(main)> FactoryBot.reload
[8] pry(main)> FactoryBot.attributes_for(:product_cancel)
=> {
:title => "iPad",
:vendor => "Apple",
:state => :canceled,
:canceled_at => 2018-02-22 22:22:22 +0900
}
[9] pry(main)> FactoryBot.attributes_for(:product_cancel, time: false)
=> {
:title => "iPad",
:vendor => "Apple",
:state => :canceled,
:canceled_at => nil
}
Tips
factory
の引数にはtraits
やブロック(do``end
)などを指定できます。
(traits
のブロックは1項目なら{}
で1行で記述できます。)
factory :product_ipod_touch, traits: [:base, :activate] do
title 'iPod touch'
end
traits
とブロックでフィクスチャをスッキリと管理することができます。 (キリッ
[10] pry(main)> FactoryBot.reload
[11] pry(main)> FactoryBot.attributes_for(:product_ipod_touch)
=> {
:title => "iPod touch",
:vendor => "Apple",
:state => :active
}
Example
紹介したサンプルはこちらです。
FactoryBot.define do
factory :product do
title 'iPad'
trait :modify do
title 'iPhone'
end
transient do
time true
end
trait :base do
vendor 'Apple'
end
trait :activate do
state :active
end
trait :cancel do
state :canceled
canceled_at { Time.now if time }
end
factory :product_activate, traits: [:base, :activate]
factory :product_cancel, traits: [:base, :cancel]
factory :product_ipod_touch, traits: [:base, :activate] do
title 'iPod touch'
end
factory :product_ipod_nano, traits: [:base, :activate] { title 'iPod nano' }
factory :product_ipod_shuffle, traits: [:base, :activate] { title 'iPod shuffle' }
factory :product_ipod_classic, traits: [:base, :activate] { title 'iPod classic' }
end
end