使用自定义验证器时RSpec失败

时间:2011-11-14 10:45:57

标签: ruby-on-rails ruby validation rspec

我在rails 3.1项目中使用了这种验证。

validates_presence_of :sales_price
validates_presence_of :retail_price
validates_numericality_of :sales_price, :greater_than => 0,
                          :allow_blank => true
validates_numericality_of :retail_price, :greater_than => 0,
                          :allow_blank => true

validate :sales_price_less_than_retail

def sales_price_less_than_retail
  if sales_price >= retail_price
    errors.add(:sales_price, "must be less than retail price.")
  end
end

我正在使用rspec测试模型。当我只使用rails标准验证助手时,一切都很好。但是当我写自定义验证器(sales_price_less_than_retail)时,测试开始失败。

以下是测试代码:

it { should validate_presence_of :sales_price }
it { should validate_presence_of :retail_price }
it { should validate_numericality_of :sales_price }
it { should validate_numericality_of :retail_price }

这是工厂:

Factory.define :offer_option do |f|
  f.sales_price          rand(21) + 10  # $10-$30
  f.retail_price         { |a| a.sales_price * 2 }
end

当我运行测试时,我得到了这样的错误:

故障:

1)OfferOption

Failure/Error: it { should validate_presence_of :sales_price }
 NoMethodError:
   undefined method `>=' for nil:NilClass
 # ./app/models/offer_option.rb:38:in `sales_price_less_than_retail'
 # ./spec/models/offer_option_spec.rb:18:in `block (2 levels) in <top (required)>'

2)OfferOption

 Failure/Error: it { should validate_presence_of :retail_price }
 ArgumentError:
   comparison of BigDecimal with nil failed
 # ./app/models/offer_option.rb:38:in `>='
 # ./app/models/offer_option.rb:38:in `sales_price_less_than_retail'
 # ./spec/models/offer_option_spec.rb:19:in `block (2 levels) in <top (required)>'

我想一切都应该没问题,因为rspec应该单独测试验证器,但它似乎在我的测试中调用validates_presence_of之后调用自定义验证器。 当我删除自定义验证器时,问题就消失了。

我做错了什么?

1 个答案:

答案 0 :(得分:6)

我认为这是因为validate_presence_of rspec helper set offer_option.sales_price = nil然后调用有效?在offer_option上。当调用有效?时,它会运行所有验证,因此您的自定义验证也是如此。然后你得到这个错误,因为nil上没有'&gt; ='方法。

如果您将sales_price_less_than_retail更改为:

def sales_price_less_than_retail
  return if sales_prices.blank? || retail_price.blank?

  if sales_price >= retail_price
    errors.add(:sales_price, "must be less than retail price.")
  end 
end

然后它应该有用。