Rails :less_than 验证使 RSpec 测试失败
Rails :less_than validation makes RSpec test fail
使用:
- Ruby2.6.6
- Rails6.0.2.2
我有一个模型,Part
,它有 2 个字段,quantity_available
和 minimum_order
。
我进行了以下验证以确保:
minimum_order
和 quantity_available
必须存在
minimum_order
和 quantity_available
不能为 0 或负数
minimum_order
的值不能高于 quantity_available
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 项验证完全按预期工作,但测试中的问题是一项验证实际上妨碍了另一项验证,这显然会导致测试的通过出现问题。
此时,我看到有两个选项可以继续:
- 让这个特定的测试也为
minimum_order
字段设置一个 nil 值。
这会导致一些小的代码重复,总的来说还不够好
- 如果
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 }
这样一来,所有测试都是绿色的,不需要任何变通方法,而且我很确定我的模型在验证检查中效率最高
使用:
- Ruby2.6.6
- Rails6.0.2.2
我有一个模型,Part
,它有 2 个字段,quantity_available
和 minimum_order
。
我进行了以下验证以确保:
minimum_order
和quantity_available
必须存在minimum_order
和quantity_available
不能为 0 或负数minimum_order
的值不能高于quantity_available
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 项验证完全按预期工作,但测试中的问题是一项验证实际上妨碍了另一项验证,这显然会导致测试的通过出现问题。
此时,我看到有两个选项可以继续:
- 让这个特定的测试也为
minimum_order
字段设置一个 nil 值。
这会导致一些小的代码重复,总的来说还不够好
- 如果
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 }
这样一来,所有测试都是绿色的,不需要任何变通方法,而且我很确定我的模型在验证检查中效率最高