はじめに
FactoryBotを使うにあたって、既に存在するファクトリーで定義されているものと違うファクトリーで試したい、または一部変更してテストしたい場面があった。
その際にいくつかやり方があったので残しておく。
環境
Ruby 2.5.1
Rails 5.1.6
Rspec 3.8
factory_bot_rails 4.11.1
前提
- Userモデルのモデルスペックを書いている
- 既に以下のファクトリーが作成済みで他のメソッドのテストで使用されている
factory :user, class: 'User' do
id { '1' }
gender { nil }
last_name { '鞘師' }
first_name { '里保' }
last_name_yomi { 'sayashi' }
first_name_yomi { 'riho' }
email { '' }
phone_number { nil }
end
- テストを追加するにあたって作成済みのファクトリーの属性の値を変更したい
- 例) genderを
female
male
に設定したい - 例) birth_atというモデルで定義されている属性を追加したい
- 例) 属性の値がまるまる違うuser2を用意したい
- 例) genderを
attributeの値を変更してテストを実行する方法3つ
上記で挙げたような要望を叶えるには主に3つやり方がある。
classを指定して新たなファクトリーを作成
まずは例で3つめに挙げたまるまる新たにファクトリーを作成する方法
この方法を取る場合は、既にあるファクトリーが書かれているファイルに追記する形になる。
この際大事なのが、対象のクラスを明記すること。通常モデル名を指定するところを自作の名前に変えているので、どのクラスでnewしてあげるべきなのかを明示しないとuninitialize constant User2
というエラーが出る。
factory :user2, class: 'User' do
id { '2' }
gender { 'male' }
last_name { '勇気' }
first_name { '須藤' }
last_name_yomi { 'sudo' }
first_name_yomi { 'yuki' }
birth_at { Date.new(2000, 11, 12) }
email { 'hoge@sample.com' }
phone_number { '0X011112222' }
end
ファクトリー側は準備ができたので、spec側の設定をする。
RSpec上で使う変数名とbuild(またはcreate)するファクトリーの名前は一致してなくても大丈夫。
let(:user) { build(:user2) }
traitを使う
次に、属性定義の一部変更を纏めたい場合に使えるのがtrait
。
こちらはまるまる新たにファクトリーを作成しないので、ファクトリーのファイルがスッキリするし、テストでも使いやすい。
:user
をbuildした後にuserをブロックで回して属性に値を指定できる。
複数の属性でもまとめられる。
trait :male do
after(:build) do |user|
user.gender = 'male'
user.birth_at = '1998,12,11'
end
end
spec側では、既に作成してあったuserに、:male
を追加でtraitを指定する。
let(:user) { build(:user,:male) }
spec側で指定
一番お手軽なのがこの方法だった。
spec側だけの設定で済むので楽で、可読性も高いように感じた。
属性と値をセットで引数として渡してあげる。
let(:user) { build(:user, gender: 'no_selected') }
まとめ
それぞれ合うケース合わないケースがあると思うので適宜使い分けていきたい。