FactoryBot のランダム特性

概要

FactoryBot を使用して、次のように特性をランダムに返したいと考えています。

FactoryBot.define do
  factory :user do

    [:active, inactive].sample

    trait :active do
      active { true }
      ...
    end
    trait :inactive do
      active { false }
      ...
    end
  end
end

そのためには:

(1..5).map{ |e| FactoryBot.build(:user) }.map(&:active?)
=> [true, false, false, true, false]

実際は次のようなものです:

FactoryBot.define do
  factory :user do
    active                    { [true, false].Sample }
    name                      { "name-#{SecureRandom.uuid}" }
    birthday                  { active == true ? rand(18..99).years.ago - rand(0..365).days.ago : nil }
    preferred_contact_method  { active == true ? %w(phone email).sample : nil }
    activated_at              { active == true ? rand(1..200).days.ago : nil }
    contact_phone_number      { preferred_contact_method == "phone" ? "+33XXXXXXXXX" : nil }
    contact_email             { preferred_contact_method == "email" ? "[email protected]" : nil }
  end
end

それは可能ですか?

解決策

これはかなり古い質問ですが、OPと同じニーズがあり、解決策を見つけたと思います。残念ながら、それはきれいではありません。

FactoryBot.define do
  factory :user do
    active { nil }

    initialize_with do
      if active.nil?
        build :user, %i[active inactive].sample, attributes
      else
        User.new(attributes)
      end
    end
    
    trait :active do
      active { true }
      ...
    end
    trait :inactive do
      active { false }
      ...
    end
  end
end

FactoryBot.create_list(:user, 5).map(&:active) #=> random array of booleans
FactoryBot.create_list(:user, 5, :active).all?(&:active?) #=> true