Ruby on rails Rails 5.2 rspec-如何测试模型是否实际使用自定义验证器?
我创建了一个自定义验证器,它有自己的特定单元测试来检查它是否工作 在那里使用should matchers添加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
会使用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 DigitValidator record.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