Test::More для начинающих

Документ является частичным переводом Test::More. By Michael G Schwern. Copyright 2001-2002, 2004-2006.

  1. Используемая терминология
  2. Руководство Test::More
  3. Использование основных функций
    1. ok
    2. is, isnt
    3. like
    4. unlike
    5. cmp_ok
    6. pass, fail
  4. Тестирование объектно-ориентированного кода
    1. can_ok
    2. isa_ok
  5. Тестирование модулей
    1. use_ok
    2. require_ok
  6. Тестирование сложных структур данных
    1. is_deeply
  7. Диагностика
    1. diag
  8. Условное тестирование
    1. TODO: BLOCK
    2. SKIP: BLOCK
    3. todo_skip
  9. Дополнительные функции сравнения
    1. eq_hash
    2. eq_set
  10. Полезные ссылки
  11. Рекомендуемая литература


Используемая терминология

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

Руководство Test::More

Руководство написано с использованием публикации Test::More. By Michael G Schwern. Copyright 2001-2002, 2004-2006 и является ее частичным переводом. Все примеры созданы автором специально для данного руководства.

Модуль Test::More поставляется со стандартным дистрибутивом Perl начиная с версии 5.8. Модуль для более ранней версии можно взять в CPAN. Модуль работает со всеми версиями Perl, начиная с версии 5.6.

Test::More - это полноценный фреймворк (framework) для написания тестовых скриптов. Имеет множество специализированных функций.

Синтаксис

Использование основных функций

ok

Функция просто проверяет переданное ей выражение ($got eq $expected) на истинность. Если выражение истинно - тест пройден, если выражение ошибочно - тест не пройден.

$test_name - это очень короткое описание текущего теста, которое будет выведено на экран рядом с результатами теста. Использование $test_name не является обязательным, но т.к. работа с исходным кодом теста, благодаря ему, существеннно облегчается, лучше его использовать.

Пример:

Вывод:

is, isnt

Подобно ok(), is() и isnt(), получают два аргумента и сравнивают их между собой с помощью "eq" и "ne", соответственно. Если сравнение прошло успешно, то тест считается пройденным.

В чем преимущество is() и isnt() перед ok()? is() и isnt() в случае неуспешного прохождения теста, предоставляют более подробный отчет о произошедших ошибках.

Пример:

Первый аргумент is() - это переменная для сравнения, второй аргумент - то, чем должна являться указанная переменная. Если $name не соответствует эталону, тест будет признан не успешным.

Вывод:

like

like() проводит сравнение первого аргумента (в данном случае, переменной $got) со вторым, которое является регулярным выражением.

Пример:

Вывод:

unlike

Действия unlike() противоположны действиям like(). unlike() получает первый аргумент, сравнивает его со вторым, который является регулярным выражением. Но тест признается успешно пройденным, если соответствия между аргументами (в отличие от like() ), НЕ найдено.

cmp_ok

Функция представляет собой нечто среднее, между ok() и is(). Она позволяет сравнивать два полученных аргумента, самостоятельно задавая оператор для сравнения. При этом, можно использовать любые бинарные операторы perl.

Пример:

Вывод:

pass, fail

Используется, просто для вывода сообщения пользователю, что тест пройден (pass) или не пройден (fail). Применять данные функции можно в случаях, когда процедура теста была написана без использования функций Test::More.

Пример:

Вывод:

Тестирование объектно-ориентированного кода

can_ok

Функция can_ok() позволяет проверить, есть ли у модуля ($module) или объекта ($object) возможность работы с методами (или функциями), указанными в списке @methods.

Пример:

Вывод:

Независимо от того, сколько функций (методов) будет перечислено в массиве @methods, выполнение can_ok() будет засчитано как выполнение ОДНОГО теста.

Если Вы хотите, чтобы проверка каждого метода (функции) проходила как отдельный независимый тест, следует использовать подобную конструкцию:

isa_ok

Проверяет, был ли создан объект и принадлежит ли он искомому классу (если не принадлежит, функция сообщит истинный класс объекта).

Пример:

Вывод:

Тестирование модулей

use_ok

Функция позволяет удостовериться, что подключение модуля c помощью команды use проходит успешно.

Помимо теста, функция автоматически подключает к тесту модуль, делая его доступным для использования. Т.е. выполняет работу директивы use:

Можно дополнительно задать массив @imports, который будет содержать список функций, которые мы хотели бы из указанного модуля импортировать. В этом случае будет проведена проверка возможности импорта для каждой из указанных функций.

Пример:

Вывод:

Разница между использованием use_ok и use состоит в том, что если с подключением модуля возникнут проблемы, при использовании use_ok работа тестового сценария не будет прервана, и все тесты, за исключением тех, для работы которых необходим подключаемый модуль (они заранее обречены на неудачу в данном случае), будут выполнены.

require_ok

Смысл работы require_ok() аналогичен use_ok(). За исключением того, что проверяется возможность подключения дополнительных модулей (или файлов) не с помощью use, а через require.

Тестирование сложных структур данных

is_deeply

Вышеприведенных функций может оказаться недостаточно, если возникнет необходимость сравнить достаточно сложные структуры данных. Для сравнения 2х сложных структур данных можно использовать функцию is_deeply().

Синтаксис функции is_deeply() похож на is(), за исключением того, что $got и $expected должны являться ссылками на структуры данных. is_deeply () будет сравнивать содержимое структур. Если в процессе сравнения будут найдены отличия - пользователь получит сообщение и указание места, где начинаются различия.

Пример:

Вывод:

Диагностика

Во время выполнения тестов, написанных с использованием Test::More, пользователь получает информацию об ошибках. В большинстве случаев, этих сообщений будет достаточно для поиска ошибок. Но при необходимости, можно дополнить стандартные диагностические сообщения, своими текстами.

diag

@diagnostic_message - массив текстовых сообщений, который будет выведен в дополнение к стандартным диагностическим сообщениям в указанной вами ситуации.

Пример:

Вывод:

Условное тестирование

Если тесты пишутся раньше, чем программный код, то они изначально обречены на неудачу. Существует ряд ситуаций, когда мы заранее знаем, что тест потерпит неудачу, и не обращаем на это внимание.

Модуль Test::More предусматривает такой вариант развития событий и позволяет пометить некоторые тесты, как неготовые к использованию (TODO). Это делает возможным добавление в тесты блоков программного кода для тестирования функциональных возможностей, которые в тестируемой программе пока отсутствуют. Во время тестирования подобные тесты будут помечены как непройденные или пропущенные.

Использование TODO позволяет избежать возникновения экстренных ситуаций, аварийного завершения работы тестирующей программы, при тестировании временного отсутствующих (или незавершенных) модулей, функций или подпрограмм.

TODO: BLOCK

Объявляет блок тестов, выполнение которых может завершиться неудачей (возможно потому, что вы еще не закончили разработку нужных функций и модулей, или знаете об ошибке, но не успели ее исправить). $why - содержит строку-объяснение, почему тесты могут быть не выполнены. $condition - условие, при котором будет выводиться строка $why, необязательный параметр.

Пример:

Вывод:

SKIP: BLOCK

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

Для пропуска нужно пометить выбранные тесты как блок SKIP. В процессе тестирования модуль Test::More не станет исполнять помеченный SKIP тест, в отличие от блоков TODO, которые выполняются в любом случае. В начале блока вызывается функция skip(), которая указывает причину, по которой производится пропуск тестов и их количество.

Рекомендуется использовать SKIP как можно реже, в виду их не совсем правильной работы. Лучше, когда это возможно, использовать блоки TODO. Тесты SKIP лучше использовать только в исключительных случаях, когда они имеют характер необязательных.

С помощью SKIP: мы объявляем блок тестов, выполнение которых при определенных условиях должно быть пропущено. $why - причина, по которой выполнение тестов не происходит, $how_many - сколько тестов не выполнено, $condition - условие, которое определяет выполнение тестов.

Пример:

Вывод:

Когда Test::More пропускает тест, он выводит сообщение ok специального вида, чтобы сохранить порядок нумерации тестов и заодно сообщить тестирующей программе о том, что произошло.

todo_skip

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

В подобных случаях лучше полностью пропускать тесты, которые не будут успешно пройдены, не пытаясь их выполнить.

Синтаксис todo_skip аналогичен синтаксису skip. Все тесты, которые будут указаны в приведенном блоке, при запуске тестирования отмечаются как завершившиеся ошибкой.

Пример:

Вывод:

Дополнительные функции сравнения

Нижеприведенные функции в настоящее время используются все реже, т.к. практически не предоставляют диагностической информации об ошибках, и фактически даже не является тестом (их не нужно учитывать в строке use Test::More tests => 2;). Эти функции появились раньше, чем is_deeply(), который сейчас их фактически заменил.

Функции использовались преимущественно в связке с ok().

is_deeply() имеет явные преимущества, предоставляя достаточно подробное описание происходящих ошибок и имея более лаконичную форму записи:

Вполне вероятно, что со временем, eq_array(), eq_hash() и eq_set() перестанут поддерживаться Test::More.

eq_array

Проводит сравнение массивов на идентичность содержания. Может проверять сложные, вложенные структуры массивов.

Пример:

Вывод:

eq_hash

Проводит сравнение двух хэшей на полное соответствие. Может проверять вложенные структуры данных.

eq_set

Сравнивает массивы, аналогично eq_array. Отличие состоит в том, что eq_set безразличен порядок, в котором следуют элементы массива.

Пример:

Вывод:

Эту же задачу можно решить с помощью is_deeply():

Полезные ссылки

RU

webscript.ru. Десять наиболее важных практик разработки на Perl.

EN

http://search.cpan.org/~mschwern/Test-Simple-0.80/lib/Test/More.pm