Introduction
Railsでhas_many
やbelongs_to
などのアソシエーションのあるモデルをfactory_botで生成する方法のメモ。
いままでずっと、
FactoryBot.define do
factory :author do
name { "Author Name" }
end
factory :book do
author_id { 1 }
title { "Book Title" }
end
end
# ~~~ #
background do
@author = create(:author)
@book1 = create(:book, author_id: @author.id, title: "book 1")
@book2 = create(:book, author_id: @author.id, title: "book 2")
@book3 = create(:book, author_id: @author.id, title: "book 3")
@book4 = create(:book, author_id: @author.id, title: "book 4")
@book5 = create(:book, author_id: @author.id, title: "book 5")
end
# ~~~ #
みたいな書き方をしてしまっていたのですが、それぞれの項目は連番とかでよいテストではもっといい方法がありました...
前提
Author has_many Books (Authorモデルは0以上のBookモデルを子に持つ)
Book belongs_to Author (Bookモデルは1つのAuthorモデルを親に持つ)
Author |
---|
id:integer |
name:string |
Book |
---|
id:integer |
author_id:integer |
title:string |
ちなみにselenium
+rspec
+capybara
でsystem testをするのを想定してます。
Rails on Dockerにて、Headless ChromeでSystem Testをやってみた。 - Qiita
また、使用しているfactory_botのversionは5.0.2
です。
Solusion
FactoryBot.define do
factory :author do
name { "Author Name" }
factory :author_with_books do
transient do
books_count { 5 }
end
after(:create) do |author, evaluator|
create_list(:book, evaluator.books_count, author: author)
end
end
end
factory :book do
title { generate(:book_title) }
end
sequence :book_title do |n|
"Book Title #{n}"
end
end
これで
-
create(:author)
でBook
を持たないAuthor
-
create(:author_with_books)
でBook
を5つ持つAuthor
が作れるようになりました。create(:author_with_books)
でできるBook
の数は7行目のbooks_count
で変更できます。
また、Book
のtitle
をgenerate(:book_title)
としています。これは19行目のsequence :book_title
を呼び出していますが、sequence
は呼び出されるたびにn
がカウントアップするため、Book Title 1
, Book Title 2
, ・・・、といったtitle
のBook
オブジェクトが5つできることになります。
# ~~~ #
background do
@author = create(:author_with_books)
end
# ~~~ #
テストシナリオファイル側では1行で1つのAuthor
オブジェクトとそれに紐づく5つのBook
オブジェクトを扱えるようになります。Book
オブジェクトは、@author.books[i]
の形でアクセスすることができます。
Conclusion
テストシナリオファイルがかなりスッキリしました。
Getting Started見る限り、まだまだ知らない便利な書き方がありそう。ちゃんと読まねば。