Учебное пособие Michael Hartl Rails: assert_not делает прямо противоположное тому, что должно, и я не понимаю, почему
tl;dr Допустимые имена не записываются в базу данных, потому что тест не пройден, а недопустимые имена записываются в базу данных, потому что тест проходит.
Изменить: Для разъяснения по поводу проекта и моего вопроса в целом: как описано в книге, эта модель пользователя настроена как начальная стадия, чтобы позволить пользователю веб-сайта в конечном итоге войти в веб-сайт. Столбцы базы данных будут "имя" и "электронная почта", и каждая строка будет один пользователь (при условии, что имя пользователя и адрес электронной почты были действительными). Я отредактировал свой оригинальный пост ниже для дальнейшего разъяснения, и все изменения выделены курсивом.
Кроме того, отвечайте, только если вы можете объяснить код, как в моем посте - не предлагайте добавлять дополнительный код, чтобы он работал. Учебник, над которым я работаю, утверждает, что этот код должен работать как есть, но, похоже, он оценивает противоположное, что должен. Наконец, если вы знаете другие ссылки, которые объясняют это более подробно, это полезно; однако я уже прочитал apidock, RoR API и большинство SO-ссылок, которые отображаются в поиске Google, и ни одна из них не помогла в объяснении этой проблемы.
Я работаю над учебником Майкла Хартла по Ruby on Rails. Я в главе 6 работаю с проверочными тестами и застрял в проверке на наличие имени. Похоже, что он делает прямо противоположное тому, что учебник говорит, что должен делать (то есть, проверяет недопустимую запись имени), хотя я точно следовал этому учебнику. Я также искал в Интернете и SO для получения дополнительной информации о том, как assert_not
работает, но не могу найти никаких полезных деталей. Вот процесс, который я прошел.
Добавьте тест, который, как мы знаем, потерпит неудачу:
require 'test_helper' class UserTest < ActiveSupport::TestCase def setup @user = User.new(name: "Example User", email: "user@example.com") end # resolves to true and passes test "should be valid" do assert @user.valid? end test "name should be present" do @user.name = " " assert_not @user.valid? end end
Все идет нормально. Я прекрасно понимаю этот код, и хотя формулировка второго теста неудобна, я интерпретирую assert_not @user.valid?
работать так: @user.valid?
оценивается как true, так как проверки не были установлены, поэтому тест думает, что имя со всеми пробелами является допустимым. Этому предшествует assert_not
который преобразует истинное значение в ложное, и делает тест неудачным.
Мы добавляем проверочный тест:
class User < ActiveRecord::Base validates :name, presence: true end
Это устанавливает правило проверки для модели User, которая обеспечивает :name
Объект имеет содержимое и не является nil, пустой строкой или пробелом. Пока все еще хорошо.
Здесь все становится сложнее. На данный момент выражение
@user.valid?
в нашем тесте следует (и имеет) значение false, поскольку правило проверки не позволяет:name
только с пробелами в нем. Я добавил комментарии вместе с этим кодом, чтобы помочь моему разуму увидеть, какие значения назначаются и оцениваются в этом процессе:test "name should be present" do @user.name = " " # => name: " " email: "example@example.com" assert_not @user.valid? # => assert_not false => true end
@user.valid?
оценивается как ложное, что делает весь assert_not
выражение оценивается как истина, и, таким образом, тест проходит. В псевдокоде эта строка может выглядеть так: assert_not (is the user valid? no)
==> assert_not(false)
==> true
, Аналогичным образом, "Мы не утверждаем, что пользователь является ложным", что оценивается как истинное.
Вот где моя проблема: тест проходит недопустимое значение для :name
Таким образом, разрешается запись имени, состоящего из пробелов, в базу данных, когда это в точности противоположно тому, что мы пытаемся достичь, а именно, предотвращение записи пустых имен в базу данных.
Наоборот, я разработал эту логику с правильным именем:
test "name should be present" do # => name: "Example User" email: "example@example.com" assert_not @user.valid? # assert_not true => false end
В этом случае, так как @user.valid?
оценивается как истина (так как "Пример пользователя" является допустимым именем), assert_not @user.valid?
оценивается как ложное, тест не пройден, и наше действительное имя не записывается в базу данных. В псевдокоде эта строка может выглядеть так: assert_not (is the user valid? yes)
==> assert_not(true)
==> false
, Аналогичным образом, "Мы не утверждаем, что пользователь является истинным", что оценивается как ложное. Поскольку тест оценивается как ложное (даже с истинным / действительным именем пользователя), это действительное имя не записывается в базу данных.
Если бы кто-то мог объяснить, как это имеет какой-то смысл, я был бы очень признателен, и подробные ответы, проведенные со мной, были бы еще лучше
2 ответа
Тест передает недопустимое значение для:name, что позволяет записать имя, состоящее из пробелов, в базу данных...
assert_not возвращает true (так же, как прохождение теста), если следующее выражение @user.valid?
, возвращает ложь. По сути, тест в разделе 3 гласит: мы не утверждаем, что пользователь действителен. Так как это ожидание / утверждение верно, оно возвращает true и тест проходит. Ничего не было сохранено в базе данных.
Вы можете добавить валидацию при добавлении строки " ", состоящей из двух пробелов
class User < ActiveRecord::Base
validates :name, presence: true, allow_blank: false
validate :name_of_valid
def name_of_valid
self.errors.add :base, 'My string can not be empty' if self.name == " "
end
end
а потом
test "name should be present" do
@user.name = " "
# => name: " " email: "example@example.com"
assert_not @user.valid?
# => assert_not true
end
У меня такая же проблема. Только сpresence: true
тест не проходит, и когда я добавляю allow_blank: false
это проходит.