#ruby-on-rails #ruby #validation #unique #minitest
#ruby-on-rails #ruby #проверка #уникальный #minitest
Вопрос:
В моем приложении Rails я пытаюсь сохранить MAC-адреса для устройств, принадлежащих разным пользователям. Каждый MAC-адрес должен быть уникальным, поэтому я включил проверку уникальности. Сама проверка, похоже, работает, поскольку дублирующиеся записи были отклонены, когда я попытался использовать консоль Rails ( ActiveRecord::RecordNotUnique
). Однако мой тест для проверки того, что могут быть сохранены только уникальные записи, не выполняется.
Итак, мои вопросы:
- Почему мой тест проваливается и как я могу это исправить?
- Я читал в другом месте, что проверка уникальности сама по себе не является надежным способом гарантировать уникальность. Должен ли я использовать другие методы, такие
before_save
как обратные вызовы?
Это сообщение об ошибке, которое я получаю для теста:
Expected #<MacAddress id: nil, user_id: nil, address: "MACADD123", created_at: nil, updated_at: nil> to be nil or false
Настройка в моих файлах модели:
# app/models/mac_address.rb
class MacAddress < ApplicationRecord
validates :address, uniqueness: true
belongs_to :user
end
# app/models/user.rb
class User < ApplicationRecord
has_many :mac_addresses, dependent: :destroy
end
Тест для проверки уникальности:
class MacAddressTest < ActiveSupport::TestCase
test 'mac address must be unique' do
new_mac = 'MACADD123'
assert MacAddress.create(user: User.first, address: new_mac)
assert MacAddress.all.pluck(:address).include?(new_mac)
# The 'assert_not' below is failing.
assert_not MacAddress.create(user: User.second, address: new_mac)
end
end
Заранее спасибо за любую помощь.
Комментарии:
1. Что касается 2) вы должны добавить ограничение уникальности в базу данных в дополнение к вашей проверке.
2. Чтобы запустить проверку , вы могли бы просто
assert MacAddress.new(...).invalid?
. Если вы хотите убедиться, что не было создано никаких дополнительных записей, возможно, было бы лучше проверить, чтоMacAddress.count
остается неизменным.3. @Stefan Я добавил ограничение уникальности в базу данных, когда создавал миграцию. Также обратите внимание на другие ваши пункты. Спасибо!
Ответ №1:
Согласно документации по create
:
Обратите внимание, что для этой записи нет id
. Это не было сохранено. Проверьте наличие ошибок с помощью .errors.full_messages
, чтобы увидеть сбой проверки уникальности.
Результирующий объект возвращается независимо от того, был ли объект успешно сохранен в базе данных или нет.
Вы должны утверждать, что он сохранен, например:
mac_address = MacAddress.create(...)
assert !mac_address.new_record?
Где это говорит вам, было ли оно сохранено или нет. В качестве альтернативы вы можете использовать, create!
который вызовет ActiveRecord::RecordInvalid
сбой.
Комментарии:
1. Спасибо! Как вы указали, ошибка заключалась в том, что
create
метод вернул объект независимо от того, был ли он фактически сохранен в БД. Решается путем утверждения, сохранен он или нет.2. В качестве примечания
persisted?
метод сообщает вам, была ли сохранена модель. На практике это противоположноnew_record?
, но может сделать ваши тесты более удобочитаемыми.
Ответ №2:
Для дальнейшего использования и для всех, кто просматривает этот вопрос — я переписал свой тест с помощью save
вместо create
, как показано ниже:
test 'mac address must be unique' do
test_address = 'MACADD123'
original_mac = MacAddress.new(user: User.first, address: test_address)
duplicate_mac = MacAddress.new(user: User.second, address: test_address)
assert original_mac.save
assert MacAddress.pluck(:address).include?(test_address)
assert_not duplicate_mac.save
duplicate_mac.errors.messages[:address].include?('has already been taken')
end
Комментарии:
1. Вы также можете утверждать, что сообщение о дублировании было добавлено как ошибка, а не то, что оно не было сохранено по каким-либо причинам, которые могут быть несвязанными.