使用FactoryBot的随机特征

时间:2019-03-20 18:59:56

标签: ruby factory-bot

我想使用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" ? "toto@tati.com" : nil }
  end
end

有可能这样做吗?

2 个答案:

答案 0 :(得分:0)

在研究最终答案时,我遇到了一个事实,即trait仅在给出块之后才执行。我将暂时分享我正在使用的代码示例,尽管如果您对其进行测试,则将只有活动用户或不活动用户,而不会同时拥有这两个用户。


您可以将特征的逻辑导出为两个lambda,然后随机选择一个:

trait_active = lambda do |context|
    context.active { true }
    #...
end
trait_inactive = lambda do |context|
    context.active { false }
    # ...
end

FactoryBot.define do
    factory :user do
        trait :active do
            trait_active.call(self)
        end
        trait :inactive do
            trait_inactive.call(self)
        end
        trait :schrodinger do
            [trait_active, trait_inactive].sample.call(self)
        end
    end
end

lambda中的context属性在这里非常重要,您可以了解更多 关于in this answer

答案 1 :(得分:0)

这是一个很老的问题,但与 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