Как проверить, какая проверка не выполнена в ActiveRecord?
У меня есть такая модель:
class User < ActiveRecord::Base
validates_length_of :name, :in => (2..5)
end
Я хочу проверить это подтверждение:
it "should not allow too short name" do
u = User.new(:name => "a")
u.valid?
u.should have(1).error_on(:name)
end
Но тогда он не проверяет, какая ошибка была установлена на name
. Я хочу знать, если это было too_short
, too_long
, или, возможно, какая-то другая проверка не удалась.
Я могу найти текст сообщения в массиве ошибок, например:
u.errors[:name].should include(I18n.t("activerecord.errors.models.user.attributes.name.too_short"))
Но это не удастся, если я установил activerecord.errors.messages.too_short
в файл локали вместо сообщения, специфичного для модели.
Итак, можно ли проверить, какая ошибка произошла?
Ответы
Ответ 1
Rails добавлен метод запроса ошибок для ActiveModel в конце 2011 года и Rails v3.2. Просто проверьте, была ли соответствующая ошибка #added?
:
# An error added manually
record.errors.add :name, :blank
record.errors.added? :name, :blank # => true
# An error added after validation
record.email = '[email protected]'
record.valid? # => false
record.errors.added? :email, :taken # => true
Обратите внимание, что для параметризуемых валидаций (например, :greater_than_or_equal_to
) вам также необходимо передать значение параметра.
record.errors.add(:age, :greater_than_or_equal_to, count: 1)
record.errors.added?(:age, :greater_than_or_equal_to, count: 1)
Ошибки идентифицируются с помощью ключа i18n. Вы можете найти соответствующие ключи, чтобы проверить соответствующий Rails i18n файл для любого языка под .
Некоторые другие полезные вопросы, которые вы можете задать ActiveModel#Error
, #empty?
и
#include?(attr)
, а также все, что вы можете задать Enumerable
.
Ответ 2
Мне действительно не нравится идея перевода переведенных сообщений об ошибках в хэш ошибок. После разговора с коллегами-рубистами я закончил обезглавливать хэширование ошибок, поэтому сначала сохраняет неизменяемое сообщение.
module ActiveModel
class Errors
def error_names
@_error_names ||= { }
end
def add_with_save_names(attribute, message = nil, options = {})
message ||= :invalid
if message.is_a?(Proc)
message = message.call
end
error_names[attribute] ||= []
error_names[attribute] << message
add_without_save_names(attribute, message, options)
end
alias_method_chain :add, :save_names
end
end
Затем вы можете протестировать следующим образом:
u = User.new(:name => "a")
u.valid?
u.errors.error_names[:name].should include(:too_short)
Ответ 3
Я рекомендую проверить gem shoulda для обработки этих типов повторных тестов проверки. Он дополняет RSpec или Test:: Unit, поэтому вы можете написать краткие спецификации, такие как:
describe User do
it { should ensure_length_of(:name).is_at_least(2).is_at_most(5) }
end
Ответ 4
Подход, который я использую:
it "should not allow too short name" do
u = User.new(:name => "a")
expect{u.save!}.to raise_exception(/Name is too short/)
end
Я использую регулярное выражение для соответствия сообщению об исключении, потому что в сообщении об исключении может быть много сообщений проверки, но мы хотим убедиться, что он содержит определенный фрагмент, связанный с слишком коротким именем.
Этот подход связывает ваши утверждения с вашими сообщениями о проверке, поэтому, если вы каждый измените свое сообщение о проверке, вам, скорее всего, также придется изменить свои спецификации. В целом, хотя это простой способ утверждать, что проверки выполняют свою работу.