Является ли идиоматичным Ruby для добавления метода assert () в класс ядра Ruby? - PullRequest
71 голосов
/ 29 сентября 2008

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

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

Ответы [ 5 ]

91 голосов
/ 11 августа 2009

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

 raise "This is wrong" unless expr

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

28 голосов
/ 20 сентября 2011

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

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

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

14 голосов
/ 29 сентября 2008

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

Как это:

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

  # define more assertions here
end

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

class Object
  include Assertions
end

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

6 голосов
/ 03 июня 2010

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

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

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

4 голосов
/ 30 сентября 2008

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

Тем не менее, утверждение Python (для меня, по крайней мере) более похоже на C assert (3) . Он не предназначен специально для юнит-тестов, а скорее для ловли случаев, когда «этого никогда не должно быть».

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

...