Как проверить, какая проверка не удалась в ActiveRecord? - PullRequest
26 голосов
/ 07 ноября 2010

У меня есть такая модель:

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 в файле локали вместо сообщения для конкретной модели.

Итак, можно ли проверить, какая ошибка произошла?

Ответы [ 4 ]

39 голосов
/ 28 мая 2013

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 = 'taken@email.com'
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 для любого языка в разделе error .

Некоторые другие изящные вопросы, которые вы можете задать ActiveModel#Error: #empty? и #include?(attr), а также все, что вы можете попросить Enumerable.

12 голосов
/ 25 ноября 2010

Мне действительно не нравится идея поиска переведенных сообщений об ошибках в хэше Errors. После разговора с коллегами по Rubyists я прекратил исправлять обезьяны, исправляя хэш ошибок, поэтому он сначала сохраняет непереведенное сообщение.

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)
5 голосов
/ 15 октября 2012

Подход, который я использую:

it "should not allow too short name" do
  u = User.new(:name => "a")
  expect{u.save!}.to raise_exception(/Name is too short/)
end

Я использую регулярное выражение для сопоставления с сообщением об исключении, поскольку в сообщении об исключении может быть много сообщений проверки, но мы хотим убедиться, что оно содержит конкретный фрагмент, относящийся кимя слишком короткое.

Этот подход объединяет ваши утверждения с вашими сообщениями о проверке, поэтому, если вы будете каждый раз изменять свое сообщение о проверке, вам, вероятно, потребуется также изменить свои спецификации.В целом, это простой способ утверждать, что валидации выполняют свою работу.

5 голосов
/ 07 ноября 2010

Я рекомендую проверить гем musta для обработки этих типов повторных проверочных тестов.Он дополняет RSpec или Test :: Unit, так что вы можете написать краткие спецификации, такие как:

describe User do
  it { should ensure_length_of(:name).is_at_least(2).is_at_most(5) }
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...