Программирование на языке Ruby - [190]

Шрифт
Интервал

Исторически сложилось так, что программисты не всегда тестируют как положено. Объясняют это обычно тем, что тесты трудно готовить и прогонять, что вся процедура требует ручного вмешательства или отнимает слишком много времени.

В 1990 году в сообществе программистов стала распространяться «культура тестирования». Идеи экстремального программирования и управляемой тестами разработки начали овладевать умами разработчиков по всему миру.

Являетесь ли вы твердокаменным приверженцем идеологии «тестируй с самого начала», не так существенно. Важно, что любой человек может воспользоваться инструментами, которые позволяют автоматизировать тестирование, упростив написание и прогон тестов.

Такие инструменты, как >Test::Unit и ZenTest, написать на Ruby было проще в силу динамичности и гибкости языка. Не менее легко и (посмею ли сказать?) приятно ими пользоваться. Внес изменение в программу, а потом смотришь, как все тесты успешно доходят до конца, — положительно в этом что-то есть!

Помимо этих инструментов в Ruby есть еще немало программ и библиотек для отладки, профилирования и испытания различных путей исполнения. Эта глава посвящена обзору имеющихся средств.

16.1. Библиотека Test::Unit

«Стандартный» способ автономного тестирования компонентов в Ruby — библиотека >Test::Unit Натаниэля Тэлбота (Nathaniel Talbott). Она была включена в дистрибутив Ruby еще в 2001 году.

В этой библиотеке для анализа тестового кода применяется отражение. Когда вы создаете подкласс класса >Test::Unit::TestCase, все методы, имена которых начинаются с >test, считаются тестовыми.

>require 'test/unit'


>class TC_MyTest < Test::Unit::TestCase

> def test_001

>  # ...

> end

> def test_002

>  # ...

> end

> # ...

>end

Методы необязательно нумеровать, как показано в этом примере. Это мое личное соглашение, но, конечно, есть и другие.

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

Я также предпочитаю включать некий «заголовок» в имя метода (описывающий его область действия или назначение):

>def test_053_default_to_current_directory

> # ...

>end

>def test_054_use_specified_directory

> # ...

>end

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

А если нужно организовать некую среду выполнения, для чего требуется время? Неразумно делать это для каждого теста, и мы не вправе завести для данной цели отдельный метод (поскольку поведение не должно зависеть от порядка прогона).

Если всем тестам нужна особая среда, можно воспользоваться методами класса >setup и >teardown. Возможно, вам это покажется странным, но вызываются они для каждого теста. Если вы хотите выполнить настройку один раз, перед прогоном одного конкретного или всех тестов, то можете поместить соответствующий код в тело класса раньше всех тестовых методов (или даже до самого класса).

А если после выполнения всех тестов нужно разрушить созданную среду? По техническим причинам (так уж работает библиотека >Test::Unit) сделать это трудно. «Самый лучший» способ — переопределить метод run всего комплекта тестов (но не метод класса >run), обернув его функциональность. Рассмотрим пример в листинге 16.1.

Листинг 16.1. Подготовка и разрушение среды исполнения

>require 'test/unit'


>class MyTest < Test::Unit::TestCase


> def self.major_setup

>  # ...

> end


> def self.major_teardown

>  # ...

> end


> def self.suite

>  mysuite = super        # Вызвать метод suite родителя.


>  def mysuite.run(*args) # Добавить синглетный метод

>   MyTest.major_setup

>   super

>   MyTest.major_teardown

>  end


>  mysuite                # и вернуть новое значение.

> end


> def setup

>  # ...

> end


> def teardown

>  # ...

> end


> def test_001

>  # ...

> end


> def test_002

>  # ...

> end


> # ...

>end

Вряд ли вы будете поступать так часто. О методе >suite мы поговорим чуть позже, а пока продолжим рассмотрение отдельных тестов.

Что должно входить в тест? Нужно как-то решить, прошел он или нет. Для этой цели применяются утверждения.

Простейшее утверждение — это метод >assert. Он принимает проверяемый параметр и еще один необязательный параметр (сообщение). Если значение параметра истинно (то есть все, кроме >false и >nil), тест прошел. В противном случае тест не прошел — тогда печатается сообщение, если оно было задано.

Есть и другие методы для формулирования утверждений. Обратите внимание, что «ожидаемое» значение всегда предшествует «фактическому».

>assert_equal(expected, actual)     # assert(expected==actual)

>assert_not_equal(expected, actual) # assert(expected!=actual)

>assert_match(regex, string)        # assert(regex =~ string)

>assert_no_match(regex, string)     # assert(regex string)

>assert_nil(object)                 # assert(object.nil?)

>assert_not_nil(object)             # assert(!object.nil?)

Некоторые утверждения носят более объектно-ориентированный характер:

>assert_instance_of(klass, obj) # assert(obj.instance_of? klass)


Рекомендуем почитать
Графика DirectX в Delphi

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Вторая жизнь старых компьютеров

Сейчас во многих школах, институтах и других учебных заведениях можно встретить компьютеры старого парка, уже отслужившие свое как морально, так и физически. На таких компьютерах можно изучать разве что Dos, что далеко от реалий сегодняшнего дня. К тому же у большинства, как правило, жесткий диск уже в нерабочем состоянии. Но и выбросить жалко, а новых никто не дает. Различные спонсоры, меценаты, бывает, подарят компьютер (один) и радуются, как дети. Спасибо, конечно, большое, но проблемы, как вы понимаете, этот компьютер в общем не решает, даже наоборот, усугубляет, работать на старых уже как-то не хочется, теперь просто есть с чем сравнивать.


DirectX 8. Начинаем работу с DirectX Graphics

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.