Rails :less_than 验证使 RSpec 测试失败

Rails :less_than validation makes RSpec test fail

使用:

我有一个模型,Part,它有 2 个字段,quantity_availableminimum_order

我进行了以下验证以确保:

class Part < ApplicationRecord
  validates :quantity_available, :minimum_order, presence: true
  validates_numericality_of :quantity_available, :minimum_order, only_integer: true, greater_than: 0
  validates_numericality_of :minimum_order, only_integer: true, less_than: :quantity_available
end

当我使用 rails console 手动测试它以创建与上述验证冲突的新部分时,验证工作正常,但是我的一个 RSpec 测试失败了

# RSpec
RSpec.describe Part, type: :model do
  let(:part) { Part.new(quantity_available: 250, minimum_order: 10)} 

  it 'is not valid without a Quantity Available' do
    part.quantity_available = nil
    expect(part).to_not be_valid
  end
end
# Console Error
Failures:

  1) Part basic checks is not valid without a Quantity Available
     Failure/Error: expect(part).to_not be_valid

     TypeError:
       cant convert nil into Float
     # ./spec/models/part_spec.rb:32:in `block (3 levels) in <top (required)>'

如您所见,这是一个非常简单的测试,它简单地说明没有 quantity_available 的部分应该失败,但是在这种情况下,它在技术上确实失败了,只是不是以我希望的方式失败失败了。

我最好的猜测是,它可能与在测试中将 quantity_available 声明为 nil 有关,导致某处出现电线交叉,因为它无法验证所有 3 个条件。我对 minimum_order 进行了一项测试,该测试与上述测试相同,但该测试按预期通过。

我做错了什么?

我猜符号并没有真正评估为字段值,试试 像这样传递 lambda:

validates_numericality_of :minimum_order, 
                          only_integer: true, 
                          less_than: -> { quantity_available }

我想我可能已经找到了一个很好的解决方案,它不仅仅是一个解决方法,实际上并没有解决我在测试中遇到的原始问题。

运行 以下 while in rails c 会按预期抛出验证错误:

new = Part.create(available_quantity: 0, minimum_order: 10)
new.save # => false
new.errors.full_messages # => ["Quantity available must be greater than 0", "Minimum order must be less than or equal to 0"]

如您所见,这 2 项验证完全按预期工作,但测试中的问题是一项验证实际上妨碍了另一项验证,这显然会导致测试的通过出现问题。

此时,我看到有两个选项可以继续:

  1. 让这个特定的测试也为 minimum_order 字段设置一个 nil 值。

这会导致一些小的代码重复,总的来说还不够好

  1. 如果 quantity_available 字段的当前值为 nil 或 0,则跳过验证。

这个更有意义。毕竟,第一次验证将确保 0 永远不会进入这些字段中的任何一个的数据库,因此如果 0 或 nil is 则跳过第二次验证是安全的当前的。如果不是,验证将触发,然后才会比较两个值。

那么,解决方法就很简单了;只需将 unless: 插入评估 lambda

的验证中
validates_numericality_of :minimum_order, less_than: :quantity_available, unless: -> { quantity_available.nil? || quantity_available == 0 }

这样一来,所有测试都是绿色的,不需要任何变通方法,而且我很确定我的模型在验证检查中效率最高