Factory Bot - 有没有办法根据覆盖使属性值成为条件?

Factory Bot - Is there a way to make an attribute value conditional based on overrides?

提问人:vivipoit 提问时间:6/20/2023 更新时间:6/20/2023 访问量:206

问:

我没有找到解决方案,但发现了几年前这个悬而未决的问题:工厂女孩 - 知道何时在工厂中覆盖属性

我的想法是,我希望工厂能够根据调用时被覆盖的内容做出决策。create

示例如下:

class Contract < ApplicationRecord
  # has start_date and end_date attributes

  has_many :visits
end

class Visit < ApplicationRecord
  # has date attribute

  belongs_to :contract

  validates :date, within_period: true # throws error if date < contract.start_date or date > contract.end_date
end

如果工厂如下所示:Visit

FactoryBot.define do
  factory :visit do
    association :contract, start_date: Date.current, end_date: Date.current
    date { Date.current }
  end
end

规格会遇到这种情况:

# Case 1
create(:visit) # creates a valid visit with Date.current in everything, which is ok

# Case 2
create(:visit, date: '01/01/2001') # does not create a visit, because it throws the date error

# Case 3
create(:visit, contract: @contract) # could create a visit or throw the date error, depending on @contract's attributes

如果工厂有办法知道什么被覆盖了:

在案例 2 中,它可以将日期发送到实际使用被覆盖日期的合同工厂。

在案例 3 中,它可以根据收到的合约对象将自己的日期设置为通过验证的日期。

似乎这可以通过诸如特征之类的东西来解决,或者可能使用特征。不过,我想知道这些方法是否会被认为违背了某些测试原则,因为它们会让测试必须了解并关心这条规则,即使测试本身可能根本不是关于日期的。create(:visit, contract: @contract, date: @contract.start_date)

现在,我想我将解决并推进第一种方法,因此规范将明确构建符合验证规则的对象,但我很好奇人们已经看到、尝试过或会推荐什么。

Ruby-on-Rails 验证 rSpec 关联 factory-bot

评论

0赞 mechnicov 6/20/2023
您是否尝试测试电源轨验证?如果这是你的目标,你就不需要它。有AAA原则,准备有效的对象(第一个A),然后在你的测试中使用它(第二个和第三个A)
0赞 vivipoit 6/21/2023
这与测试验证无关。这是关于使这种验证成为测试通常不必了解或准备的东西。

答:

3赞 Siim Liiser 6/20/2023 #1

您可以使用实例变量来查看传递到方法中的内容。@overridescreate

FactoryBot.define do
  factory :visit do
    # if contract is passed use contract.start_date as date
    # Date.current otherwise
    # if date is given, the block is ignored.
    date { @overrides[:contract]&.start_date || Date.current }
    # If contract is not given, build a contract with dates from the date attribute
    association :contract, start_date: date, end_date: date
  end
end

如果这不适用于无块关联定义,则可以更改为带有块的关联定义。

评论

0赞 vivipoit 6/21/2023
我喜欢这个解决方案。我确实必须更改关联才能使其正常工作。谢谢!contract { association :contract, start_date: date, end_date: date }