Является ли Ruby идиоматическим добавление метода Assert() в класс ядра Ruby?
Вопрос
Я расширяю свое понимание Ruby, написав на Ruby эквивалент xUnit Кента Бека.Python (на котором пишет Кент) имеет широко используемый метод Assert().Руби нет.Я думаю, добавить это будет легко, но является ли Kernel подходящим местом для этого?
КСТАТИ, Я знаю о существовании различных фреймворков Unit в Ruby. - это упражнение для изучения идиом Ruby, а не для того, чтобы «что-то сделать».
Решение
Нет, это не лучшая практика.Лучшая аналогия с Assert() в Ruby — это просто повышение
raise "This is wrong" unless expr
и вы можете реализовать свои собственные исключения, если хотите обеспечить более конкретную обработку исключений.
Другие советы
Я думаю, что использование утверждений в Ruby вполне допустимо.Но вы говорите о двух разных вещах:
- Фреймворки xUnit используют
assert
методы проверки ожиданий от тестов.Они предназначены для использования в тестовом коде, а не в коде приложения. - Некоторые языки, такие как C, Java или Python, включают
assert
конструкция, предназначенная для использования внутри кода ваших программ для проверки ваших предположений об их целостности.Эти проверки встроены внутри самого кода.Это утилиты не для тестирования, а для разработки.
Я недавно написал твердое_утверждение:небольшая библиотека Ruby, реализующая утилиту утверждения Ruby а также пост в моем блоге, объясняющий его мотивацию..Это позволяет вам писать выражения в форме:
assert some_string != "some value"
assert clients.empty?, "Isn't the clients list empty?"
invariant "Lists with different sizes?" do
one_variable = calculate_some_value
other_variable = calculate_some_other_value
one_variable > other_variable
end
И их можно деактивировать так assert
и invariant
оцениваются как пустые утверждения.Это позволит вам избежать проблем с производительностью в производстве.Но заметьте, что Прагматичные программисты не рекомендую их деактивировать.Вам следует деактивировать их только в том случае, если они действительно влияют на производительность.
Что касается ответа о том, что идиоматический способ Ruby использует обычный raise
высказыванию, мне кажется, ему не хватает выразительности.Одно из золотых правил ассертивного программирования — не использовать утверждения для нормальной обработки исключений.Это две совершенно разные вещи.Если вы используете один и тот же синтаксис для обоих из них, я думаю, ваш код будет более непонятным.И, конечно же, вы теряете возможность их деактивировать.
Вы можете убедиться, что использование утверждений — это хорошо, потому что две обязательные к прочтению классические книги, такие как Программист-прагматик: от подмастерья до мастера и Код завершен посвящайте им целые разделы и рекомендуйте их использование.Еще есть хорошая статья под названием Программирование с утверждениями они очень хорошо иллюстрируют, что такое ассертивное программирование и когда его использовать (оно основано на Java, но концепции применимы к любому языку).
По какой причине вы добавили метод Assert в модуль ядра?Почему бы просто не использовать другой модуль под названием Assertions
или что-то?
Так:
module Assertions
def assert(param)
# do something with param
end
# define more assertions here
end
Если вам действительно нужно, чтобы ваши утверждения были доступны повсюду сделайте что-то вроде этого:
class Object
include Assertions
end
Отказ от ответственности:Я не проверял код, но в принципе сделал бы так.
Это не особенно идиоматично, но я думаю, что это хорошая идея.Особенно если сделать так:
def assert(msg=nil)
if DEBUG
raise msg || "Assertion failed!" unless yield
end
end
Таким образом, если вы решите не запускать DEBUG (или какой-либо другой удобный переключатель, в прошлом я использовал Kernel.do_assert), это не повлияет.
Насколько я понимаю, вы пишете свой собственный набор тестов, чтобы лучше познакомиться с Ruby.Таким образом, хотя Test::Unit может быть полезен в качестве руководства, вероятно, это не то, что вам нужно (потому что он уже выполнил свою работу).
Тем не менее, утверждение Python (по крайней мере, для меня) более похоже на C. утверждать(3).Он не предназначен специально для модульных тестов, а скорее для выявления случаев, когда «этого никогда не должно происходить».
Встроенные модульные тесты Ruby склонны рассматривать проблему так: каждый отдельный класс тестовых примеров является подклассом Прецедент, и это включает в себя оператор «assert», который проверяет достоверность переданной ему информации и записывает ее для отчета.