【问题标题】:Rails :less_than validation makes RSpec test failRails :less_than 验证使 RSpec 测试失败
【发布时间】:2020-08-18 05:07:58
【问题描述】:

使用:

  • Ruby 2.6.6
  • Rails 6.0.2.2

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

我有以下验证以确保:

  • minimum_orderquantity_available 必须存在
  • minimum_orderquantity_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 导致某处电线交叉,因为它无法验证所有三个条件。我对minimum_order 进行了一个测试,与上面的测试相同,但测试通过了。

我在这里做错了什么?

【问题讨论】:

  • 可能是因为only_integer 期望它是一个整数,而nil 不是一个整数。它在幕后做这件事。你可以做一个expect raise_error
  • 我没有想到 only_integer 位,但这是有道理的。删除了它,但同样的事情仍然发生,所以现在我只是将测试转换为expect { part.save }.to raise_error TypeError,它现在就可以了。干杯!
  • 您确定这是预期行为吗?我认为这是解决方法。
  • @AmitPatel 你是对的,它确实感觉像是一种忽略问题的解决方法。请参阅下面的答案

标签: ruby-on-rails ruby unit-testing validation rspec


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    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 字段也具有零值。

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

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

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

    因此,解决方案非常简单;只需将 unless: 粘贴到评估 lambda 的验证中

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多