create_list
は、複数のインスタンスを作成するときに便利なメソッドですが、作成されるインスタンスのテストデータは同じになってしまいます。
create_list(:article, 3, title: 'test', description: 'test')
create
メソッドで愚直に1つずつインスタンスを作成すれば、以下のように渡す引数をインスタンスごとに変えることはできますが、
create(:article, title: 'test1', description: 'test') create(:article, title: 'test2', description: 'test') create(:article, title: 'test3', description: 'test')
でもそれは面倒なのでもっと簡潔に書きたい、できれば一行で...という場合もあると思います。 そこで、一行で書ける解決方法について模索したのでまとめてみます。
1. 配列をループさせてインスタンス作成するときに渡す引数を変える
タイトルをユニークな値にしたいので、ユニークな値を持った配列をループさせてcreate
メソッドでインスタンスを作成します。
['test1', 'test2', 'test3'].each { |title| create(:article, title: title, description: 'test') }
2. 先にインスタンスを作成し、後からインスタンスの持つ値を変更する
create_list
メソッドで一気にインスタンスを作成し、後からタイトルを変更するパターンです。注意すべきなのは、create_list
メソッドで初期データはDBに保存されますが、後で書き換えられたタイトルは保存されていないので、再度save
する必要があります。
create_list(:article, 3, title: 'test', description: 'test') { |v, i| v.title = 'test' + i.to_s }.map(&:save!)
3. そもそもFactoryBotの定義でユニークな値になるようにすればいい
そもそも論かもしれませんが、最初からsequence
を使ってtitleがユニークになるようにしとけばOKかもですね。
FactoryBot.define do factory :article do sequence(:title) { |n| "test#{n}" } description { 'test' } end end create_list(:article, 3)
sequence
を使ってtitleがユニークになるように定義していても、テストケースによってはデフォルト値から変更したい場合も発生すると思うので、上記の2パターンが有効な場合もありそうです。