当属性保存在模型的回调中时,shoulda-matchers 失败

shoulda-matchers fail when attribute saved in a model's callback

class StudentPiggyBank < ActiveRecord::Base
  PERIODS = [['tydzień', :week], ['miesiąc', :month], ['trzy miesiące', :three_months]]
  RATES_MULTIPLIERS = {week: 1, month: 1.5, three_months: 2}
  INTEREST_RATE_PRECISION = 2
  before_validation :set_interest_rate
  validates :completion_date, presence: true
  validates :balance, numericality: {greater_than_or_equal_to: 0,
                                     message: I18n.t('errors.messages.negative_piggy_bank_balance')}
  validates :interest_rate, numericality: {greater_than_or_equal_to: 0,
                                           message: I18n.t('errors.messages.negative_interest_rate')}


  def self.date_from_param(period_param)
    case period_param
      when 'week'
        1.week.from_now
      when 'month'
        1.month.from_now
      when 'three_months'
        3.months.from_now
    end
  end

  protected

  def set_interest_rate
    num_of_days = completion_date - Date.today
    if num_of_days >= 90
      self.interest_rate = student.base_interest_rate.mult(RATES_MULTIPLIERS[:three_months], INTEREST_RATE_PRECISION)
    elsif num_of_days >= 30
      self.interest_rate = student.base_interest_rate.mult(RATES_MULTIPLIERS[:month], INTEREST_RATE_PRECISION)
    else
      self.interest_rate = student.base_interest_rate.mult(RATES_MULTIPLIERS[:week], INTEREST_RATE_PRECISION)
    end
  end
end

此代码有效。但是,在使用 shoulda-matchers

进行测试时
describe StudentPiggyBank do
  it { should validate_numericality_of(:interest_rate).is_greater_than_or_equal_to(0) }
  it { should validate_numericality_of(:balance).is_greater_than_or_equal_to(0) }
end

我收到行 num_of_days = completion_date - Date.today:

的错误
 NoMethodError:
       undefined method `-' for nil:NilClass

为什么 completion_datenil

嗯,it 基本上会做一个 described_class.new,所以你不会有一个 completion_date。您可以这样修复它:

describe StudentPiggyBank do
  context 'with a completion date' do
    before { subject.completion_date = 7.days.from_now }

    it { should validate_numericality_of(:interest_rate).is_greater_than_or_equal_to(0) }
  end
end