Хэл Фултон - Программирование на языке Ruby
- Название:Программирование на языке Ruby
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2007
- Город:Москва
- ISBN:5-94074-357-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Хэл Фултон - Программирование на языке Ruby краткое содержание
Ruby — относительно новый объектно-ориентированный язык, разработанный Юкихиро Мацумото в 1995 году и позаимствовавший некоторые особенности у языков LISP, Smalltalk, Perl, CLU и других. Язык активно развивается и применяется в самых разных областях: от системного администрирования до разработки сложных динамических сайтов.
Книга является полноценным руководством по Ruby — ее можно использовать и как учебник, и как справочник, и как сборник ответов на вопросы типа «как сделать то или иное в Ruby». В ней приведено свыше 400 примеров, разбитых по различным аспектам программирования, и к которым автор дает обстоятельные комментарии.
Издание предназначено для программистов самого широкого круга и самой разной квалификации, желающих научиться качественно и профессионально работать на Ruby.
Программирование на языке Ruby - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Я также предпочитаю включать некий «заголовок» в имя метода (описывающий его область действия или назначение):
def test_053_default_to_current_directory
# ...
end
def test_054_use_specified_directory
# ...
end
Кроме прочего, неплохо оставлять хотя бы однострочный комментарий, касающийся цели и смысла теста. Вообще говоря, у каждого теста должна быть только одна цель.
А если нужно организовать некую среду выполнения, для чего требуется время? Неразумно делать это для каждого теста, и мы не вправе завести для данной цели отдельный метод (поскольку поведение не должно зависеть от порядка прогона).
Если всем тестам нужна особая среда, можно воспользоваться методами класса setup
и teardown
. Возможно, вам это покажется странным, но вызываются они для каждого теста. Если вы хотите выполнить настройку один раз, перед прогоном одного конкретного или всех тестов, то можете поместить соответствующий код в тело класса раньше всех тестовых методов (или даже до самого класса).
А если после выполнения всех тестов нужно разрушить созданную среду? По техническим причинам (так уж работает библиотека Test::Unit
) сделать это трудно. «Самый лучший» способ — переопределить метод run всего комплекта тестов (но не метод класса run
), обернув его функциональность. Рассмотрим пример в листинге 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)
assert_kind_of(klass, obj) # assert(obj.kind_of? klass)
assert_respond_to(obj, meth) # assert(obj.respond_to? meth)
Другие относятся к исключениям и символам, которые генерируются методом throw
. Понятно, что такие методы принимают блок.
assert_nothing_thrown { ... } # Не было throw.
assert_nothing_raised { ... } # Не было raise.
assert_throws(symbol) { ... } # Символ в результате throw.
assert_raises(exception) { ... } # Исключение в результате raise.
Есть еще несколько утверждений, но эти применяются чаще всего и отвечают почти всем потребностям. Дополнительную информацию можно найти в онлайновой документации на сайте http://ruby-doc.org.
Имеется еще метод flunk
, который всегда завершается неудачно. Можно считать, что это некий вид заглушки.
Если при запуске тестового файла вы ничего специально не указываете, то по умолчанию вызывается консольный исполнитель тестов. Это возвращает нас к старой доброй технологии 1970-х годов. Имеются и другие исполнители, например графический Test::Unit::UI::GTK::TestRunner
. Любой исполнитель тестов можно вызвать, обратившись к его методу run
, которому передается специальный параметр, описывающий набор тестов:
class MyTests < Test::Unit::TestCase
# ...
end
# Явное указание исполнителя тестов...
runner = Test::Unit::UI::Console::TestRunner
runner.run(MyTests)
Параметром может быть любой объект, обладающий методом suite
, который возвращает объект, представляющий комплект тестов. Что все это означает?
Познакомимся к понятием комплекта тестов ближе. Оказывается, комплект тестов может состоять из набора тестов или набора подкомплектов. Следовательно, можно сгруппировать тесты так, что будет прогоняться либо только один набор, либо сразу все.
Пусть, например, есть три набора тестов, и вы хотите прогнать их как единый комплект. Можно было бы поступить так:
require 'test/unit/testsuite'
require 'tc_set1'
require 'tc_set2'
require 'ts_set3'
class TS_MyTests
def self.suite
mysuite = Test::Unit::TestSuite.new
mysuite << TC_Set1.suite
mysuite << TC_Set2.suite
mysuite << TS_Set3.suite
return mysuite
end
end
Test::Unit::UI::Console::TestRunner.run(TS_MyTests)
Но такая сложность ни к чему. Имея отдельные наборы тестов, библиотека Test::Unit
в состоянии просмотреть пространство объектов и объединить их все в один комплект. Поэтому следующий код тоже будет работать (и даже вызывать подразумеваемый по умолчанию исполнитель тестов):
require 'test/unit'
require 'tc_set1'
require 'tc_set2'
require 'ts_set3'
Библиотека Test::Unit
располагает и другими возможностями, а в дальнейшем, вероятно, будет усовершенствована. Самую свежую информацию ищите в сети.
16.2. Комплект инструментов ZenTest
Этот великолепный инструментарий написал Райан Дэвис (Ryan Davis). Основной инструмент ( zentest
) — это исполняемая программа, которая генерирует файл с тестами на основе анализа вашего кода.
Тестируемый класс ( class under test — CUT ) служит основой тестового класса (test class — ТС). На каждом уровне области видимости в начало имени класса добавляется строка Test
, а в начало имени метода — строка test_
. Иногда имена методов приходится «подправлять», например в случае с методом ==
(к имени которого нельзя добавлять никакой префикс) или если имя метода оканчивается на ?, ! или =. В листинге 16.2 приведен пример подлежащего тестированию кода:
class Alpha
class Beta
attr_accessor :foo, :bar
def initialize
end
def foo?
@foo
end
end
Интервал:
Закладка: