提问人:vivipoit 提问时间:6/20/2023 更新时间:6/20/2023 访问量:206
Factory Bot - 有没有办法根据覆盖使属性值成为条件?
Factory Bot - Is there a way to make an attribute value conditional based on overrides?
问:
我没有找到解决方案,但发现了几年前这个悬而未决的问题:工厂女孩 - 知道何时在工厂中覆盖属性
我的想法是,我希望工厂能够根据调用时被覆盖的内容做出决策。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)
现在,我想我将解决并推进第一种方法,因此规范将明确构建符合验证规则的对象,但我很好奇人们已经看到、尝试过或会推荐什么。
答:
3赞
Siim Liiser
6/20/2023
#1
您可以使用实例变量来查看传递到方法中的内容。@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
如果这不适用于无块关联定义,则可以更改为带有块的关联定义。
评论
0赞
vivipoit
6/21/2023
我喜欢这个解决方案。我确实必须更改关联才能使其正常工作。谢谢!contract { association :contract, start_date: date, end_date: date }
下一个:不允许的参数:嵌套属性(更深)
评论