如何在一个Factory内部获取另一个Factory的属性?
我明白你的需求啦——把校验逻辑从测试代码里移到工厂类,让spec代码更清爽,只用let(:picnic) { build :picnic }就能搞定。这就给你一步步拆解怎么做:
第一步:创建合法的Family工厂
首先得确保我们的Family工厂能生成满足要求的实例:让dad和son属于同一个Family且唯一。你可以在family_factory.rb里这么写:
FactoryBot.define do factory :family do # 补充Family模型的必填字段,比如家庭名称 name { Faker::Family.unique.last_name + " Family" } # 嵌套构建dad和son,强制关联到当前family实例 after(:build) do |family| # 避免重复创建,只有当不存在时才构建 family.dad = build(:user, family: family) unless family.dad.present? family.son = build(:user, family: family) unless family.son.present? end end end
注:这里假设dad和son都是User模型的实例,你可以根据实际模型名调整。如果需要唯一性,也可以给User工厂加unique约束。
第二步:构建关联的Picnic工厂
接下来在picnic_factory.rb里,直接关联上面的Family工厂,这样每次生成Picnic时,都会自动带上一个合法的Family(已经满足dad和son同属一个家庭的要求):
FactoryBot.define do factory :picnic do # 关联合法的Family实例 family { build(:family) } # 补充Picnic模型的其他必填字段 location { Faker::Address.park } date { Date.today + rand(7).days } # 额外做个兜底校验,确保完全符合scope要求(可选,但更严谨) after(:build) do |picnic| picnic.family.dad.family_id = picnic.family.id picnic.family.son.family_id = picnic.family.id end end end
第三步:在Spec里简化调用
现在你的测试代码就可以完全简化了,不用再写一堆前置构建逻辑,直接用工厂方法:
RSpec.describe Picnic do let(:picnic) { build :picnic } it "passes the family member scope validation" do expect(picnic).to be_valid end # 其他测试用例... end
这样做的好处很明显:所有的依赖构建和校验逻辑都封装在工厂里,spec代码更简洁易读,后续如果Family或Picnic的校验规则变了,只需要修改工厂类,不用挨个改测试用例。
内容的提问来源于stack exchange,提问作者Timmy Von Heiss
相关产品推荐
相关产品推荐

