Ruby on rails Rails 5.2 rspec-如何测试模型是否实际使用自定义验证器?

Ruby on rails Rails 5.2 rspec-如何测试模型是否实际使用自定义验证器?,ruby-on-rails,validation,rspec,ruby-on-rails-5,customvalidator,Ruby On Rails,Validation,Rspec,Ruby On Rails 5,Customvalidator,我创建了一个自定义验证器,它有自己的特定单元测试来检查它是否工作 在那里使用should matchers添加会使用matcher验证\u,因此您可以编写: subject.validates_with(:custom_validator) 这一建议被拒绝是完全正确的,因为它并没有真正测试模型的行为 但是我的模型有4个使用自定义验证器的字段,我希望对这4个字段的行为进行测试,即这4个字段正在被验证,就像我正在测试它们是否存在一样: describe '#attribute_name' do

我创建了一个自定义验证器,它有自己的特定单元测试来检查它是否工作

在那里使用should matchers添加
会使用
matcher验证\u,因此您可以编写:

subject.validates_with(:custom_validator)
这一建议被拒绝是完全正确的,因为它并没有真正测试模型的行为

但是我的模型有4个使用自定义验证器的字段,我希望对这4个字段的行为进行测试,即这4个字段正在被验证,就像我正在测试它们是否存在一样:

describe '#attribute_name' do
  it { is_expected.to validate_presence_of(:attribute_name) }
end
那么,我如何编写一个基本上做相同事情的测试,类似这样的测试:

describe '#attribute_name' do
  it { is_expected.to use_custom_validator_on(:attribute_name) }
end
问同样的问题,答案建议建立一个测试模型。但是,我的验证器需要一个选项,它的使用方式如下:

describe '#attribute_name' do
  it { is_expected.to use_custom_validator_on(:attribute_name) }
end
\app\models\fund.rb

我收到
RecordInvalid
错误(来自我自己的验证器!lol),说我没有为验证器提供所需的选项。该选项称为“完全正确”

1) Fund#ein validates digits
     Failure/Error: raise ActiveRecord::RecordInvalid # option :exactly was not provided (incorrect usage)

     ActiveRecord::RecordInvalid:
       Record invalid
那么Rspec是否没有“看到”模型文件中定义的值“9”

显然,在测试中定义它是没有意义的,因为这是我试图测试的定义行为。可以把它想象成
验证
{length:x}
选项测试的长度

当然,必须有一种方法来测试该自定义验证器选项是否已在模型上设置

验证程序代码

class DigitsValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    return if value.blank?

    length = options[:exactly]
    regex = /\A(?!0{#{length}})\d{#{length}}\z/
    return unless value.scan(regex).empty?

    record.errors[attribute] << (options[:message] || error_msg(length))
  end

  private

  def error_msg(length)
    I18n.t('activerecord.errors.custom.digits_attr_invalid', length: length) if length
    raise ActiveRecord::RecordInvalid # option :exactly was not provided (incorrect usage)
  end
end
class DigitValidatorrecord.errors[attribute]我认为您不应该以测试模型是否使用特定的验证器为目标。而是检查模型在特定情况下是否有效。换句话说,您应该能够在不知道实现的情况下测试模型的行为

因此,在这种情况下,您应该使用验证器的“精确”选项正确设置模型,并测试模型验证是否充分


另一方面,如果您担心将来会有人滥用验证器,并且验证器必须选择“精确”,那么您应该在每次选项不存在时都提出错误,并单独测试验证器,如此处所述:

我认为您必须添加返回语句,否?:-)

或者,在设置
长度后,移除该方法并使用防护装置:

  class DigitsValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
      return if value.blank?

      length = options[:exactly]
      raise ActiveRecord::RecordInvalid if length.nil?

      regex = /\A(?!0{#{length}})\d{#{length}}\z/
      return unless value.scan(regex).empty?

      record.errors[attribute] << 
        (options[:message] || 
          I18n.t('activerecord.errors.custom.digits_attr_invalid', length: length))
      end
    end
class DigitValidator记录。错误[属性]谢谢你的建议。验证器已经过独立测试——它有自己的单元测试。休息了五年后,我又回到了rspec,你的第二段让我意识到了我的错误。我没有在测试中正确设置模型,因此感谢您指出这一点!我有点不知所措,但我会逐步检查DigitValidator的每一行,以确保所有内容都设置正确。如果您将
binding.pry
添加到
error\u msg
方法的顶部,您可以通过在pry控制台中运行
next
逐步遍历每一行。你也可以使用
step
up
@kriskova进入和退出方法。我想我的第一个评论是错的。模型设置正确:(
 def error_msg(length)
   return I18n.t('activerecord.errors.custom.digits_attr_invalid', length: length) if length
   raise ActiveRecord::RecordInvalid # option :exactly was not provided (incorrect usage)
 end
  class DigitsValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
      return if value.blank?

      length = options[:exactly]
      raise ActiveRecord::RecordInvalid if length.nil?

      regex = /\A(?!0{#{length}})\d{#{length}}\z/
      return unless value.scan(regex).empty?

      record.errors[attribute] << 
        (options[:message] || 
          I18n.t('activerecord.errors.custom.digits_attr_invalid', length: length))
      end
    end