Это идиоматический Ruby для добавления метода assert() в класс Ruby Kernel?

Я расширяю свое понимание Ruby, кодируя эквивалент Kent Beck xUnit в Ruby. Python (который пишет Kent) имеет метод assert() на языке, который используется широко. Рубин не делает. Я думаю, что это должно быть легко добавить, но является ли ядром подходящее место для его размещения?

Кстати, я знаю о существовании различных структур Unit в Ruby - это упражнение, чтобы изучить идиомы Ruby, а не "что-то сделать".

Ответ 1

Нет, это не лучшая практика. Лучшая аналогия assert() в Ruby просто поднимает

 raise "This is wrong" unless expr

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

Ответ 2

Я думаю, что вполне реально использовать утверждения в Ruby. Но вы упоминаете две разные вещи:

  • Структуры xUnit используют методы assert для проверки ожиданий ваших тестов. Они предназначены для использования в вашем тестовом коде, а не в вашем коде приложения.
  • Некоторые языки, такие как C, Java или Python, включают конструкцию assert, предназначенную для использования внутри кода ваших программ, для проверки допущений, которые вы делаете о своей целостности. Эти проверки встроены внутри самого кода. Они не являются утилитой для тестирования, а имеют время разработки.

Недавно я написал solid_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 получают оценку как пустые операторы. Это позволит избежать проблем с производительностью при производстве. Но обратите внимание, что Pragmatic Programmers рекомендуют не деактивировать их. Вы должны дезактивировать их, только если они действительно влияют на производительность.

Относительно ответа, говорящего, что идиоматический метод Ruby использует нормальный оператор raise, я думаю, что ему не хватает выразительности. Одним из золотых правил настойчивого программирования не является использование утверждений для нормальной обработки исключений. Это две совершенно разные вещи. Если вы используете один и тот же синтаксис для двух из них, я думаю, что код будет более неясным. И, конечно же, вы теряете способность дезактивировать их.

Вы можете убедиться, что использование утверждений - это хорошо, потому что две обязательные для чтения классические книги, такие как Прагматический программист от Journeyman to Master и Code Complete посвятить им целые разделы и рекомендовать их использование. Существует также хорошая статья под названием Программирование с утверждениями, которые очень хорошо иллюстрируют, что такое напористое программирование и когда его использовать (оно основано на Java, но концепции применимы к любым язык).

Ответ 3

В чем причина добавления метода assert к модулю ядра? Почему бы просто не использовать другой модуль под названием Assertions или что-то еще?

Вот так:

module Assertions
  def assert(param)
    # do something with param
  end

  # define more assertions here
end

Если вам действительно нужны ваши утверждения, чтобы они были доступны везде, выполните следующие действия:

class Object
  include Assertions
end

Отказ от ответственности: я не тестировал код, но в принципе я сделал бы это так.

Ответ 4

Это не особенно идиоматично, но я думаю, что это хорошая идея. Особенно, если это делается следующим образом:

def assert(msg=nil)
    if DEBUG
        raise msg || "Assertion failed!" unless yield
    end
end

Таким образом, нет никакого эффекта, если вы решите не запускаться с DEBUG (или другим удобным переключателем, который я использовал Kernel.do_assert в прошлом).

Ответ 5

Мое понимание заключается в том, что вы пишете свой собственный набор тестов, чтобы стать более знакомым с Ruby. Поэтому, хотя Test:: Unit может быть полезен в качестве руководства, возможно, это не то, что вы ищете (потому что оно уже выполнило задание).

Тем не менее, утверждение python (по крайней мере, для меня), более похоже на C assert (3). Это не специально предназначено для модульных тестов, а скорее для того, чтобы ловить случаи, когда "этого никогда не должно быть".

Как встроенные модульные тесты Ruby имеют тенденцию рассматривать проблему, тогда каждый отдельный класс тестового случая является подклассом TestCase и включает в себя инструкцию assert, которая проверяет достоверность того, что было передано ей, и записывает ее для отчетности.