rom*_*man 2 ruby validation rspec ruby-on-rails
我在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
Run Code Online (Sandbox Code Playgroud)
我正在使用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 }
Run Code Online (Sandbox Code Playgroud)
这是工厂:
Factory.define :offer_option do |f|
f.sales_price rand(21) + 10 # $10-$30
f.retail_price { |a| a.sales_price * 2 }
end
Run Code Online (Sandbox Code Playgroud)
当我运行测试时,我得到了这样的错误:
失败:
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)>'
Run Code Online (Sandbox Code Playgroud)
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)>'
Run Code Online (Sandbox Code Playgroud)
我想一切都应该没问题,因为rspec应该单独测试验证器,但它似乎在我的测试中调用validates_presence_of之后调用自定义验证器.当我删除自定义验证器时,问题消失.
我究竟做错了什么?
我假设这是因为validate_presence_of rspec helper set offer_option.sales_price = nil然后调用有效?在offer_option上.当调用有效?时,它会运行所有验证,因此您的自定义验证也是如此.然后你得到这个错误,因为nil上没有'> ='方法.
如果您将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
Run Code Online (Sandbox Code Playgroud)
然后它应该工作.