Techioz Blog

Factorybot でnested_attributes を持つモデルのファクトリを作成する方法

概要

RSpecで以下のコントローラーをテストしたい

クーポン_コントローラー.rb:

class Api::V1::CouponsController < ApiController
  def index
    if params[:profile_id]
      @coupons = Profile.find(params[:profile_id]).coupons
    end
  end
end

私は知りたいです

  1. FactoryBot でファクトリーを作成する方法 (spec/factories/profiles.rb、クーポン.rb、クーポン_プロファイル.rb)

2)spec/controllers/coupons_controllers.rbの書き方:

プロフィール.rb

class Profile < ApplicationRecord
  accepts_nested_attributes_for :coupon_profiles
end

クーポン.rb

class Coupon < ApplicationRecord
  has_many :coupon_profiles
end

クーポン_プロフィール.rb

class CouponProfile < ApplicationRecord
  belongs_to :coupon
  belongs_to :profile
end

解決策

何かのようなもの:

# spec/factories/profiles.rb
FactoryBot.define do
  factory :profile, class: 'Profile', do
    # ...
  end
end
# spec/factories/coupons.rb
FactoryBot.define do
  factory :coupon, class: 'Coupon' do 
    # ...
  end
end
# spec/factories/coupon_profiles.rb
FactoryBot.define do
  factory :coupon_profile, class: 'CouponProfile' do
    coupon
    profile
  end
end

正直に言うと、FactoryBot の GETTING_STARTED README を確認するのが最善の策です。知りたいことはすべてそこに例とともに記載されています。これは README の優れた例です。 (上記の例でのクラスの使用については、クラス定数の代わりに文字列化されたクラス名を使用する特定のパフォーマンス上の理由があることに注意してください)

コントローラーの仕様については、RSpec ドキュメントを確認しましたか?ただし、コントローラーの仕様ではなく、要求仕様などのより機能的なテストを使用することをお勧めします。次のようなことができるはずです:

describe 'coupons' do 
  subject { response }

  shared_examples_for 'success' do
    before { request }

    it { should have_http_status(:success) }
  end

  describe 'GET /coupons' do
    let(:request) { get coupons_path }

    it_behaves_like 'success'
  end

  describe 'GET /coupons/:profile_id' do
    let(:request) { get coupon_path(profile)
    let(:profile) { coupon_profile.profile }
    let(:coupon_profile) { create :coupon_profile }

    it_behaves_like 'success'
  end
end