ruby-on-rails 工厂机器人-是否有一种方法使属性值的条件的基础上覆盖?

ffvjumwh  于 2023-06-25  发布在  Ruby
关注(0)|答案(1)|浏览(98)

我没有找到解决办法,但发现了这个多年前未回答的问题:factory girl - know when an attribute is overridden in factory
我的想法是,我希望工厂能够根据调用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)或者使用traits来解决。然而,我想知道,如果这些方法不会被认为违背了一些测试原则,因为它们会使测试必须知道和关心这个规则,即使测试本身可能根本不是关于日期的。
现在,我想我将解决并继续使用第一种方法,因此规范将显式地构建遵守验证规则的对象,但我很好奇人们已经看到,尝试或推荐了什么。

2sbarzqh

2sbarzqh1#

您可以使用@overrides示例变量来查看传入create方法的内容。

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

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

相关问题