Программирование на языке Ruby - [191]
>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
> def initialize
> end
> def process
> end
> def process!
> end
> def ==(other)
> end
> def ===(other)
> end
>end
После запуска команды >zentest file.rb >tfile.rb
получится файл, показанный в листинге 16.3.
># Code Generated by ZenTest v. 3.2.0
># classname: asrt / meth = ratio%
># Alpha::Beta: 0 / 7 = 0.00%
>require 'test/unit' unless defined? $ZENTEST and $ZENTEST
>class TestAlpha < Test::Unit::TestCase
> def test_process
> raise NotImplementedError, 'Need to write test_process'
> end
> def test_process_bang
> raise NotImplementedError, 'Need to write test_process_bang'
> end
>end
>module TestAlpha
> class TestBeta < Test::Unit::TestCase
> def test_bar
> raise NotImplementedError, 'Need to write test_bar'
> end
> def test_bar_equals
> raise NotImplementedError, 'Need to write test_bar_equals'
> end
> def test_foo
> raise NotImplementedError, 'Need to write test_foo'
> end
> def test_foo_eh
> raise NotImplementedError, 'Need to write test_foo_eh'
> end
> def test_foo_equals
> raise NotImplementedError, 'Need to write test_foo_equals'
> end
> end
>end
># Number of errors detected: 9
Обратите внимание, что каждый тестовый метод возбуждает исключение (предложение >raise
). Идея в том, что все тесты завершаются неудачно, пока вы явно не напишете код.
Исходный файл почему-то не включается в тестовый. Можно поместить в начало тестового файла директиву >require 'file'
или эквивалентную ей (предварительно затребовав >test/unit
). Тогда тестовый код увидит определения ваших классов.
В командной строке можно указать и второй параметр. Если добавить код в тестируемый класс, то тестовые классы окажутся устаревшими. Чем обновлять их вручную, можно сгенерировать только «обновления»:
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Сейчас во многих школах, институтах и других учебных заведениях можно встретить компьютеры старого парка, уже отслужившие свое как морально, так и физически. На таких компьютерах можно изучать разве что Dos, что далеко от реалий сегодняшнего дня. К тому же у большинства, как правило, жесткий диск уже в нерабочем состоянии. Но и выбросить жалко, а новых никто не дает. Различные спонсоры, меценаты, бывает, подарят компьютер (один) и радуются, как дети. Спасибо, конечно, большое, но проблемы, как вы понимаете, этот компьютер в общем не решает, даже наоборот, усугубляет, работать на старых уже как-то не хочется, теперь просто есть с чем сравнивать.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.