Я создал собственный валидатор, у которого есть свои собственные специальные юнит-тесты, чтобы проверить, что он работает.
Используя там-соответствия было предложено добавить validates_with
совпадение,так что вы могли бы написать:
subject.validates_with(:custom_validator)
Правильно было отклонено предложение, поскольку оно не проверяет поведение модели.
Но в моей модели есть 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
Этот вопрос задает то же самое, и ответ предлагает построить тестовую модель.Однако моему валидатору требуется опция, она используется следующим образом:
\ app \ models \ fund.rb
class Fund < ActiveRecord
validates :ein, digits: { exactly: 9 }
end
Так что, если я создаю тестовую модельи протестируйте его, как предложено:
it 'is has correct number of digits' do
expect(build(:fund, ein: '123456789')).to be_valid
end
it 'is has incorrect number of digits' do
expect(build(:fund, ein: '123').to be_invalid
end
Я получаю ошибку 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», определенное в файле модели?
Очевидно, что нет смысла определять это втест как это определенное поведение, которое я пытаюсь проверить.Думайте об этом, как о тестировании validates_length_of
для опции { 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
Интересное примечание
Очевидно, что если я уберу строку 'рейза' из DigitsValidator
, тогда оба теста пройдут успешно.Что-то не так с моим кодом, который я не вижу?