LoginSignup
2
1

More than 3 years have passed since last update.

【Rails】アソシエーションをもつモデルをfactory_botで作成するメモ

Last updated at Posted at 2019-04-06

Introduction

Railsでhas_manybelongs_toなどのアソシエーションのあるモデルをfactory_botで生成する方法のメモ。
いままでずっと、

spec/factories/factory.rb
FactoryBot.define do
  factory :author do
    name { "Author Name" }
  end

  factory :book do
    author_id { 1 }
    title     { "Book Title" }
  end
end
spec/system/xxxxx_spec.rb
# ~~~ #
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

spec/factories/factory.rb
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で変更できます。

また、Booktitlegenerate(:book_title)としています。これは19行目のsequence :book_titleを呼び出していますが、sequenceは呼び出されるたびにnがカウントアップするため、Book Title 1, Book Title 2, ・・・、といったtitleBookオブジェクトが5つできることになります。

spec/system/xxxxx_spec.rb
# ~~~ #
background do
  @author = create(:author_with_books)
end
# ~~~ #

テストシナリオファイル側では1行で1つのAuthorオブジェクトとそれに紐づく5つのBookオブジェクトを扱えるようになります。Bookオブジェクトは、@author.books[i]の形でアクセスすることができます。

Conclusion

テストシナリオファイルがかなりスッキリしました。
Getting Started見る限り、まだまだ知らない便利な書き方がありそう。ちゃんと読まねば。

Reference

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1