LoginSignup
2
0

More than 3 years have passed since last update.

Rspecで多対多のFactoryを作ってSystemSpecでテストしたときのノート[RSpec, FactoryBot]

Last updated at Posted at 2020-10-24

背景

Rspecで多対多の関係を作って、SystemSpecでテストをしました。
元々のテーブル構造の複雑さもあり、かなり苦労したので、以下にノートをまとめます。

実行完了は下記の通りです。

  • Rspec 3.9
  • Rails 5.2.4.2

テーブル構造

テーブル構造は、このようになっています。メインのテーブルは、offices(ある会社の支社)とshops(営業先である店舗)で、office(支社)はevebtを開いて、そこに営業先である店舗shopsが参加します。shopsは必ず何らかのcategoryを持っています。

Image from Gyazo

起こっていた問題

モデルメソッドの関係で、どうしてもeventsfactoryを作った時に、それに紐づく、shopsが必要になりました。しかし、構造上、このように書いたのでは、エラーが出てしまいました。

let!(:shop){FactoryBot.create(:shop)}
let!(:event){FactoryBot.create(:event)}
#=> ここで eventに紐づくshopがないとエラーになる構造になっていた
let!(:event_shops){FactoryBot.create(:event_shop, event: event, shop: shop)}

対処方法

そこで、eventfactory生成時に、同時に関連するshopも定義できるようなfactoryを作成することにしました。

eventsのファクトリを作る

作成したFactoryは以下のようになっています。

spec/factories/events.rb
FactoryBot.define do
  factory :event do
    office_id { nil }
    name { "テストイベント" }

    trait :with_shops do
      after(:create) do |event|
        category = FactoryBot.create(:category, :sequence)
        create_list(:shop, 1, events: [event], category: category)
      end
    end
  end
end

まず、eventのファクトリ内にwith_shopsというtraitを作成して、event作成時に関連するshopも作成できるようにします。create_listshopのファクトリを複数作成でき流ようにし(ここでは1つしか必要ないので1つだけ)、eventsからeventのインスタンスが複数入れられるように、[event]と配列で表記します。

なお、categoryがわざわざtraitを使って呼び出してあるのは、後ほど解説します。

System Specで適切に呼び出せるようにする

spec/factories/categories.rb
FactoryBot.define do
  factory :category do
    name { "医療系" }

    trait :sequence do
      sequence(:id, 100)
      name { "服飾系" }
    end
  end
end
spec/system/events_spec.rb
let!(:event) { FactoryBot.create(:event, :with_shops, office: office, shops: [shop]) }
# ここからcategoryをshopに当てはめることはできない

次に、categoryのファクトリですが、ビューの中で、eventは複数回生成されます。そのため、同時に生成されるshopcateogoryは毎回別のid(FK)にしないと、FKの重複エラーになってしまいました。

また、system specからeventshopscategoryを当てはめようとすると、spec/factories/events.rb内で、shopのファクトリを作成しようとしたときに、「外部キーが存在しません」とエラーになってしまいました。

そのため、sequenceを利用して、一つ一つ違うid(FK)のcategoryを作成するようにしました。

終わりに(参考サイトなど)

解決に長い時間がかかってしまいましたが、なんとか解決できてよかったです!
今回はDBの構造が複雑だったため、このような複雑なSpecを書かねばならなくなってしまいましたが、
今後はDB設計をしっかりして、もっとシンプルなテストで済むようにしたいです。。。。

▼特に参考にさせていただいた記事など
- FactoryGirlで「多対多」や「複数の1対多」のアソシエーションを設定する
- Factorybotのtraitを使って、has_manyが2重にある複雑なassociation付きのデータを用意する
- FactoryBot (旧FactoryGirl) の sequence と .next

2
0
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
0