【问题标题】:Random trait with FactoryBotFactoryBot 的随机特征
【发布时间】:2019-03-20 18:59:55
【问题描述】:

我想使用 FactoryBot 像这样随机返回 trait:

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

有可能吗?

【问题讨论】:

  • 写:FactoryBot.build(:user, [:active, :inactive].sample)?
  • 它可以,但你每次使用工厂时都必须考虑它。

标签: ruby factory-bot


【解决方案1】:

在研究最终答案时,我发现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。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-16
      • 1970-01-01
      • 2015-09-28
      • 2021-05-09
      • 1970-01-01
      相关资源
      最近更新 更多