54453


`FactoryBot`の関連付けの記述で常に同一の親を指定する方法がわからなかったので質問します。

以下のような関係のモデルがあり

[code]

    class User < ApplicationRecord
      has_many :trades
    end
    
    class Company < ApplicationRecord
      has_many :trades
    end
    
    class Trade < ApplicationRecord
      belongs_to :user
      belongs_to :company
    end
    
[/code]

テストのために以下のような記述をしています。

### test/factries.rb

[code]

    FactoryBot.define do
      factory :user do
        email { Faker::Internet.safe_email }
        password { Faker::Internet.password }
      end
    
      factory :company do
        code { Faker::Number.unique.number(4) }
      end
    
      factory :trade do
        sequence(:order_number)
        user
        company
      end
    end
    
[/code]

## test/models/trade_test.rb

[code]

    class TradeTest < ActiveSupport::TestCase
      def setup
        @company = create(:company)
        @user = create(:user)
      end
    
      test 'Foo' do
        create(:trade, user: @user, company: @company, price: 200)
        create(:trade, user: @user, company: @company, price: 100)
        assert(@user.foo)
      end
    end
    
[/code]

ほとんどのテストにおいて上記のように`trade`を生成する時に同一の`user`と`company`を指定するのですが、常に`user: @user,
company: @company`を記述するのは冗長なのでもっとスッキリかけないかと思っています。

`Factory.define`か`setup`内で`Trade`を作成する時はデフォルトで同じ親を持つように指定する方法はないでしょうか？


CC BY-SA 4.0
2019-04-23T05:25:39.130
54412
2019-04-24T08:52:09.903
3271
question
ruby-on-rails
FactoryBotの関連付けで常に同一の親を持つように設定する方法


一番手っ取り早いのは

[code]

    factory :trade do
      sequence(:order_number)
      user { User.first || create(:user) }
      company { Company.first || create(:company) }
    end
    
    ...
    test 'Foo' do
      create(:trade, price: 200)
      create(:trade, price: 100)
      assert(@user.foo)
    end
    
[/code]

とすることだと思います。  
ただこうしてしまうと、テストケースを見ただけでは同じ親を持つtradeだといういうことが分からないので、せめてfacotry定義を継承して作っておいた方が無難だと思います。

[code]

    factory :trade do
      sequence(:order_number)
    
      factory :trade_with_the_same_parents do
        user { User.first || create(:user) }
        company { Company.first || create(:company) }
      end
    end
    
    ...
    
      create(:trade_with_the_same_parents, price: 200)
      create(:trade_with_the_same_parents, price: 100)
    
    
[/code]

その他、factory_botの`transient`やコールバックを利用しても書けると思います。  
<https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md>

あるいはファクトリ定義はシンプルに保ち、テスト用のヘルパーメソッドを作成するという手もあると思います。

ただ、個人的には現状通りの方法で良いのではないかと思います。。。  
アプリの規模が大きくなると、ファクトリ定義ってすぐに複雑になっちゃいますし、あまりテストコード周りで凝りすぎてしまうと、テストを読むのに解析が必要になるという本末転倒な結果に陥ったりもしますし。  
テストコードは冗長であっても明示的に保ち、DRYを求めすぎないというバランスも大事だと思います。


CC BY-SA 4.0
2019-04-24T08:52:09.903
54453
2019-04-24T08:52:09.903
9608
54412
answer