前提として
Rspecで1対1の関係のモデルのテストデータを複数作りたい
うーんってなったので忘れないようついでに他のパターンも一緒にまとめました
- モデルを複数作る
- 1対1のデータを1つ作る
- 1対nのデータを1つ作る
- 1対1のデータを複数作る ←今回やりたくて悩んだのはここ
- 1対nのデータを複数作る
ここで例として扱うモデルは
1対1も含めたいのでよくある1対nの親モデルUser
と子モデルPost
にしました
まず、FactoryBotでモデルを複数作成するには
create_list
を使います
FactoryBot.create_list(:post, 3)
でPost
モデルを3つ作れる
1対1のデータを作る
パターンA
FactoryBot.create(:post, user: FactoryBot.create(:user))
パターンB
user = FactoryBot.create(:user)
FactoryBot.create(:post, user: user)
パターンC
FactoryBot.create(:user) do |u|
FactoryBot.create(:post, user: u)
end
1対nのデータを作る
パターンA
user = FactoryBot.create(:user)
FactoryBot.create_list(:post, 3, user: user)
パターンB
FactoryBot.create_list(:post, 3, user: FactoryBot.create(:user))
User : Post = 1 : 3
のデータを作ってるんですが
ぱっと見、Post : User = 1 : 1
のデータが3つできるようにも見えません?
自分はそう見えて「1対1のデータを複数作る」にはどうすれば、と悩みました
でもまぁよくよく考えてみると妥当な挙動だと思います
1対1のデータを複数作る
これこれ これがやりたかった
FactoryBot.create_list(:user, 3) do |u|
FactoryBot.create(:post, user: u)
end
1対nのデータを複数作る
1対1のデータを複数作った時点で目的達成なのですが
せっかくなのでついでに1対nについても考えてみました
パターンA(力技)
3.times do
FactoryBot.create(:user) do
FactoryBot.create_list(:post, 3, user: user)
end
end
これでもいいんですがRubocopにシバかれたので考え直してパターンBにたどり着きました
パターンB
FactoryBot.create_list(:user, 3) do |u|
FactoryBot.create_list(:post, 3, user: u)
end
これで
User : Post = 1 : 3
のデータが3つ作成されます
ブロック使うことでイメージとしてはcreate_listがfor文みたいでちょっと読みやすいような