FactoryBot创建Rollout时触发update_attribute栈溢出错误排查
Rails RSpec测试中FactoryBot设置percent_enabled触发栈溢出问题
运行RSpec测试时,只要在FactoryBot的rollout工厂里设置percent_enabled { 0 },创建实例就会抛出SystemStackError(栈溢出),错误栈指向rollout.rb第60行的percent_enabled=方法。注释掉这个赋值语句后测试正常,已经试过bundle update没用。
相关代码
工厂代码(rollouts.rb)
FactoryBot.define do factory :rollout do name { Faker::IndustrySegments.industry.parameterize.underscore } percent_enabled { 0 } offset { 0 } green_list { [] } red_list { [] } resource_type { 'User' } trait :with_user do resource_type { 'User' } end end end
模型代码(rollout.rb)
class Rollout < ApplicationRecord before_create :set_offset before_validation :uppercase_resource_type validates :name, presence: true, uniqueness: { case_sensitive: false } validates_inclusion_of :percent_enabled, in: 0..100 validates :resource_type, presence: true, inclusion: { in: %w[User Role Instrument Profile] } # ...其他方法... end
错误信息
Failures: 1) Rollout a valid Rollout that has working validations is valid with valid attributes Failure/Error: update_attribute(:percent_enabled, num) SystemStackError: stack level too deep # ./app/models/rollout.rb:60:in `percent_enabled=' # ./app/models/rollout.rb:60:in `percent_enabled=' ...
测试代码(rollout_spec.rb)
RSpec.describe Rollout, type: :model do describe 'a valid Rollout' do let(:rollout) { create(:rollout, :with_user) } context 'that has working validations' do it 'is valid with valid attributes' do print(rollout) expect(rollout).to be_valid end end end
问题原因与解决方案
栈溢出的核心原因是自定义的percent_enabled=方法内部发生了无限递归调用。虽然你提供的模型代码里没显示这个方法,但错误明确指向第60行的该方法,说明你肯定在模型里重写了这个setter。
比如错误的写法(会递归调用自己):
def percent_enabled=(num) self.percent_enabled = num.to_i # 这里每次赋值都会再次调用这个方法,无限循环 end
正确的写法应该绕过自定义setter,直接操作数据库列或者调用父类方法:
# 方法一:直接操作属性哈希 def percent_enabled=(num) self[:percent_enabled] = num.to_i end # 方法二:调用父类的setter方法 def percent_enabled=(num) super(num.to_i) end
按上述方式修改rollout.rb第60行的percent_enabled=方法后,重新运行测试即可解决栈溢出问题。
内容的提问来源于stack exchange,提问作者Meryl
相关产品推荐
相关产品推荐

