Тест
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- СИНТАКСИС
- ОПИСАНИЕ
- РУКОВОДСТВО ПО БЫСТРОМУ НАЧАЛУ
- ТИПЫ ТЕСТОВ
- ONFAIL
- ОШИБКИ И ОСОБЕННОСТИ
- ОКРУЖЕНИЕ
- ПРИМЕЧАНИЕ
- СМОТРИТЕ ТАКЖЕ
- АВТОР
НАЗВАНИЕ
Test — предоставляет простую структуру для написания скриптов тестирования
СИНТАКСИС
use strict;
use Test;
# use a BEGIN block so we print our plan before MyModule is loaded
BEGIN { plan tests => 14, todo => [3,4] }
# load your module...
use MyModule;
# Helpful notes. All note-lines must start with a "#".
print "# I'm testing MyModule version $MyModule::VERSION\n";
ok(0); # failure
ok(1); # success
ok(0); # ok, expected failure (see todo list, above)
ok(1); # surprise success!
ok(0,1); # failure: '0' ne '1'
ok('broke','fixed'); # failure: 'broke' ne 'fixed'
ok('fixed','fixed'); # success: 'fixed' eq 'fixed'
ok('fixed',qr/x/); # success: 'fixed' =~ qr/x/
ok(sub { 1+1 }, 2); # success: '2' eq '2'
ok(sub { 1+1 }, 3); # failure: '2' ne '3'
my @list = (0,0);
ok @list, 3, "\@list=".join(',',@list); #extra notes
ok 'segmentation fault', '/(?i)success/'; #regex match
skip(
$^O =~ m/MSWin/ ? "Skip if MSWin" : 0, # whether to skip
$foo, $bar # arguments just like for ok(...)
);
skip(
$^O =~ m/MSWin/ ? 0 : "Skip unless MSWin", # whether to skip
$foo, $bar # arguments just like for ok(...)
); ОПИСАНИЕ
Этот модуль упрощает задачу написания файлов тестов для модулей Perl таким образом, что их вывод находится в формате, который Test::Harness ожидает увидеть.
РУКОВОДСТВО ПО БЫСТРОМУ НАЧАЛУ
Для написания теста для вашего нового (и, вероятно, ещё не завершённого) модуля создайте новый файл под названием t/test.t (в новой директории t). Если у вас есть несколько файлов тестов, для тестирования наборов функций "foo", "bar" и "baz", то смело называйте ваши файлы t/foo.t, t/bar.t и t/baz.t
Функции
Этот модуль определяет три публичные функции, plan(...), ok(...), и skip(...). По умолчанию все три экспортируются инструкцией use Test;.
-
plan(...) -
BEGIN { plan %theplan; }Это должно быть первое, что вы вызываете в своём скрипте тестирования. Оно объявляет ваш план тестирования, сколько будет тестов, допускается ли неудача каких-либо из них и так далее.
Типичное использование выглядит так:
use Test; BEGIN { plan tests => 23 }Вот что можно поместить в параметры для plan:
-
tests => number -
Количество тестов в вашем скрипте. Это означает все вызовы ok() и skip().
-
todo => [1,5,14] -
Ссылка на список тестов, которым разрешено не пройти. См. "TODO ТЕСТЫ".
-
onfail => sub { ... } -
onfail => \&some_sub -
Ссылка на подпрограмму, которая будет выполнена в конце скрипта тестирования, если какие-либо тесты не пройдут. См. "ONFAIL".
Вы должны вызвать
plan(...)один и только один раз. Вы должны вызвать его в блокеBEGIN {...}, как показано ниже:BEGIN { plan tests => 23 } -
-
ok(...) -
ok(1 + 1 == 2); ok($have, $expect); ok($have, $expect, $diagnostics);Эта функция является причиной существования
Test. Это основная функция, которая обрабатывает вывод "ok" или "not ok", вместе с текущим номером теста. (Это то, чтоTest::Harnessхочет увидеть.)В самом простом использовании
ok(...)просто принимает одно скалярное выражение. Если его значение истинно, тест проходит; если ложно, тест не проходит. Примеры:# Examples of ok(scalar) ok( 1 + 1 == 2 ); # ok if 1 + 1 == 2 ok( $foo =~ /bar/ ); # ok if $foo contains 'bar' ok( baz($x + $y) eq 'Armondo' ); # ok if baz($x + $y) returns # 'Armondo' ok( @a == @b ); # ok if @a and @b are the same # lengthВыражение оценивается в скалярном контексте. Поэтому следующее будет работать:
ok( @stuff ); # ok if @stuff has any # elements ok( !grep !defined $_, @stuff ); # ok if everything in @stuff # is defined.Особый случай — если выражение является ссылкой на подпрограмму (в синтаксисе
sub {...}или\&foo). В этом случае она выполняется, и её значение (истина или ложь) определяет, проходит ли тест или нет. Например,ok( sub { # See whether sleep works at least passably my $start_time = time; sleep 5; time() - $start_time >= 4 });В форме с двумя аргументами
ok(arg1, arg2)сравнивает два скалярных значения, чтобы увидеть, совпадают ли они. Они совпадают, если оба неопределены, или если arg2 является регулярным выражением, которое соответствует arg1, или если они равны в соответствии сeq.# Example of ok(scalar, scalar) ok( "this", "that" ); # not ok, 'this' ne 'that' ok( "", undef ); # not ok, "" is definedВторой аргумент считается регулярным выражением, если это объект регулярного выражения или строка, которая выглядит как регулярное выражение. Объекты регулярных выражений создаются с помощью оператора qr// в последних версиях perl. Строка считается похожей на регулярное выражение, если её первый и последний символы — "/", или если первый символ — "m", а второй и последний — одинаковые символы, не являющиеся алфавитными или пробельными. Эти регулярные
Примеры регулярных выражений:
ok( 'JaffO', '/Jaff/' ); # ok, 'JaffO' =~ /Jaff/ ok( 'JaffO', 'm|Jaff|' ); # ok, 'JaffO' =~ m|Jaff| ok( 'JaffO', qr/Jaff/ ); # ok, 'JaffO' =~ qr/Jaff/; ok( 'JaffO', '/(?i)jaff/ ); # ok, 'JaffO' =~ /jaff/i;Если любой (или оба!) являются ссылками на подпрограммы, они выполняются и используются в качестве значения для сравнения. Например:
ok sub { open(OUT, '>', 'x.dat') || die $!; print OUT "\x{e000}"; close OUT; my $bytecount = -s 'x.dat'; unlink 'x.dat' or warn "Can't unlink : $!"; return $bytecount; }, 4 ;Вышеприведённый тест передаёт два значения
ok(arg1, arg2)— первый — coderef, а второй — число 4. Перед тем, какokсравнит их, он вызывает coderef и использует возвращаемое им значение в качестве реального значения этого параметра. Предполагая, что$bytecountвозвращает 4,okв конечном итоге тестирует4 eq 4. Поскольку это истинно, этот тест пройден.Наконец, вы можете добавить необязательный третий аргумент в
ok(arg1,arg2, note), где note — строковое значение, которое будет выведено, если тест не пройдёт. Это должна быть какая-то полезная информация о тесте, касающаяся причины его неудачи и/или описание теста. Например:ok( grep($_ eq 'something unique', @stuff), 1, "Something that should be unique isn't!\n". '@stuff = '.join ', ', @stuff );К сожалению, заметка не может быть использована со стилем одного аргумента для
ok(). То есть, если вы попробуетеok(arg1, note), тоTestинтерпретирует это какok(arg1, arg2), и, вероятно, в итоге протестируетarg1 eq arg2— и это не то, что вы хотите!Все вышеперечисленные специальные случаи могут иногда вызывать проблемы. См. "ОШИБКИ И ОСОБЕННОСТИ".
-
skip(skip_if_true, args...) -
Используется для тестов, которые при определённых условиях могут быть пропущены. По сути, эквивалентно:
if( $skip_if_true ) { ok(1); } else { ok( args... ); }... за исключением того, что
ok(1)выводит не только "ok testnum", но и фактически "ok testnum # skip_if_true_value".Аргументы после skip_if_true — это то, что передаётся
ok(...)если этот тест не пропущен.Пример использования:
my $if_MSWin = $^O =~ m/MSWin/ ? 'Skip if under MSWin' : ''; # A test to be skipped if under MSWin (i.e., run except under # MSWin) skip($if_MSWin, thing($foo), thing($bar) );Или, в обратном порядке:
my $unless_MSWin = $^O =~ m/MSWin/ ? '' : 'Skip unless under MSWin'; # A test to be skipped unless under MSWin (i.e., run only under # MSWin) skip($unless_MSWin, thing($foo), thing($bar) );Важно помнить, что первый параметр истиннен, если вы хотите пропустить тест, а не выполнить его; а также он служит заметкой о том, почему он пропускается. Итак, в первом фрагменте кода, читайте код как «пропустить, если MSWin — (в противном случае) протестировать, является ли
thing($foo)thing($bar)», или во втором случае «пропустить, если не MSWin…».Также, когда ваша строка skip_if_reason истинна, она действительно должна (для обратной совместимости с более старыми версиями Test.pm) начинаться со строки "Skip", как показано в приведённых выше примерах.
Обратите внимание, что в вышеприведённых случаях
thing($foo)иthing($bar)вычисляются — но до тех пор, покаskip_if_trueистинно, мыskip(...)просто выбрасываем их значение (т. е. не беспокоясь о том, чтобы обрабатывать их как значения дляok(...)). Но если вам нужно не вычислять аргументы при пропускании теста, используйте этот формат:skip( $unless_MSWin, sub { # This code returns true if the test passes. # (But it doesn't even get called if the test is skipped.) thing($foo) eq thing($bar) } );или даже этот, который по сути эквивалентен:
skip( $unless_MSWin, sub { thing($foo) }, sub { thing($bar) } );То есть, оба похожи на это:
if( $unless_MSWin ) { ok(1); # but it actually appends "# $unless_MSWin" # so that Test::Harness can tell it's a skip } else { # Not skipping, so actually call and evaluate... ok( sub { thing($foo) }, sub { thing($bar) } ); }
ТИПЫ ТЕСТОВ
-
НОРМАЛЬНЫЕ ТЕСТЫ
Ожидается, что эти тесты пройдут. Обычно большинство или все ваши тесты относятся к этой категории. Если нормальный тест не проходит, это означает, что что-то не так.
-
ПРОПУЩЕННЫЕ ТЕСТЫ
Функция
skip(...)предназначена для тестов, которые могут или не могут быть запущены в зависимости от наличия платформенных функций. Первый аргумент должен быть истинным (подумайте «да, пожалуйста, пропустите»), если требуемая функция не доступна. После первого аргументаskip(...)работает точно так же, какok(...). -
ТЕСТЫ TODO
Тесты TODO предназначены для поддержания выполнимого списка TODO. Ожидается, что эти тесты не пройдут. Если тест TODO проходит, это означает, что соответствующая функция не должна быть в списке TODO, не так ли?
Пакеты не должны выпускаться с пройденными тестами TODO. Как только тест TODO начинает работать, он должен быть преобразован в нормальный тест, а новая рабочая функция должна быть задокументирована в примечаниях к выпуску или в журнале изменений.
ONFAIL
BEGIN { plan test => 4, onfail => sub { warn "CALL 911!" } } Хотя сбои тестов должны быть достаточными, дополнительные диагностики могут быть инициированы в конце выполнения теста. onfail получает массив ссылок на хэши, описывающие каждый сбой теста. Каждый хэш будет содержать по крайней мере следующие поля: package, repetition, и result. (Не следует полагаться на наличие других полей.) Если тест имел ожидаемое значение или диагностическую (или «примечание») строку, они также будут включены.
Необязаемый хук onfail может быть использован просто для вывода версии вашего пакета и/или способа сообщения о проблемах. Он также может быть использован для создания чрезвычайно сложных диагностик для особенно странной неудачи теста. Однако это не панацея. Сбросы ядра или другие необратимые ошибки препятствуют запуску хука onfail. (Он выполняется внутри блока END.) Кроме того, onfail вероятно избыточен в большинстве случаев. (Ваш код теста должен быть проще, чем код, который он тестирует, да?)
ОШИБКИ И ОСОБЕННОСТИ
-
ok(...)— специальная обработка строк, которые похожи на регулярные выражения, может также вызывать неожиданное поведение. Невинный пример:ok( $fileglob, '/path/to/some/*stuff/' );не сработает, поскольку Test.pm рассматривает второй аргумент как регулярное выражение! Лучше всего использовать одноаргументную форму:
ok( $fileglob eq '/path/to/some/*stuff/' ); -
ok(...)— использование строкиeqиногда может вызывать странные проблемы при сравнении чисел, особенно если вы преобразуете строку в число:$foo = "1.0"; ok( $foo, 1 ); # not ok, "1.0" ne 1Лучше всего использовать одноаргументную форму:
ok( $foo == 1 ); # ok "1.0" == 1 -
Как вы могли предположить из вышеприведенной документации и примеров, прототип
ok—($;$$)(и, между прочим, прототипskip—($;$$$)). Это означает, например, что вы можете выполнитьok @foo, @barдля сравнения размера двух массивов. Но не обманывайтесь, думая, чтоok @foo, @barозначает сравнение содержимого двух массивов — вы сравниваете только количество элементов каждого. Так легко ошибиться при чтенииok @foo, @bar, поэтому лучше быть явным и написатьok scalar(@foo), scalar(@bar). -
Это почти наверняка не сделает того, чего вы ожидаете:
ok $thingy->can('some_method');Почему? Потому что
canвозвращает ссылку на подпрограмму, означающую «да, это возможно (и метод такой-то)», а затемokвидит ссылку на подпрограмму и думает, что вы передаёте функцию, которую хотите вызвать и рассмотреть истинность результата! Точно так же, как:ok $thingy->can('some_method')->();Вместо этого вам, вероятно, нужно вот это:
ok $thingy->can('some_method') && 1;Если
canвозвращает ложь, то это значение передаётся вok. Если оно возвращает истину, то более широкое выражение$thingy->can('some_method') && 1возвращает 1, чтоokвоспринимает как простой сигнал успеха, как вы и ожидаете. -
Синтаксис
skip— примерно единственный возможный, но всё равно довольно запутанный. Просто начните с вышеприведённых примеров, и всё будет хорошо.Кроме того, пользователи могут ожидать, что это:
skip $unless_mswin, foo($bar), baz($quux);не будет вычислять
foo($bar)иbaz($quux)при пропускании теста. Но на самом деле они вычисляются, ноskipпросто не будет беспокоиться о их сравнении, если$unless_mswinистинно.Вы могли бы сделать так:
skip $unless_mswin, sub{foo($bar)}, sub{baz($quux)};Но это не очень красиво. В долгосрочной перспективе может оказаться проще или понятнее просто действовать следующим образом:
if( $^O =~ m/MSWin/ ) { print "# Yay, we're under $^O\n"; ok foo($bar), baz($quux); ok thing($whatever), baz($stuff); ok blorp($quux, $whatever); ok foo($barzbarz), thang($quux); } else { print "# Feh, we're under $^O. Watch me skip some tests...\n"; for(1 .. 4) { skip "Skip unless under MSWin" } }Но убедитесь, что
okвызывается ровно столько раз в первом блоке, сколькоskipвызывается во втором блоке.
Среда
Если переменная среды PERL_TEST_DIFF установлена, она будет использоваться как команда для сравнения неожиданных результатов в несколько строк. Если у вас установлен GNU diff, вы можете установить PERL_TEST_DIFF на diff -u. Если у вас нет подходящей программы, вы можете установить модуль Text::Diff, а затем установить PERL_TEST_DIFF на perl -MText::Diff -e 'print diff(@ARGV)'. Если PERL_TEST_DIFF не установлена, но модуль Algorithm::Diff доступен, он будет использоваться для отображения различий в результатах на нескольких строках.
ПРИМЕЧАНИЕ
Бывший разработчик этого модуля однажды сказал, что он больше не активно развивается. Однако слухи о его кончине сильно преувеличены. Обратная связь и предложения очень приветствуются.
Обратите внимание, что основное достоинство этого модуля — его простота. Обратите внимание, что существуют уже более амбициозные модули, такие как Test::More и Test::Unit.
В некоторых более ранних версиях этого модуля в документации были некоторые путающие опечатки в описании skip(...).
СМОТРИТЕ ТАКЖЕ
Test::Simple, Test::More, Devel::Cover
Test::Builder для построения собственной библиотеки тестирования.
Test::Unit — интересная библиотека тестирования в стиле XUnit.
Test::Inline позволяет встраивать тесты в код.
АВТОР
Copyright (c) 1998-2000 Joshua Nathaniel Pritikin.
Copyright (c) 2001-2002 Michael G. Schwern.
Copyright (c) 2002-2004 Sean M. Burke.
Текущий основной разработчик: Jesse Vincent. <jesse@bestpractical.com>
Этот пакет — свободное программное обеспечение и предоставляется «как есть» без явных или подразумеваемых гарантий. Он может использоваться, перераспределяться и/или изменяться на тех же условиях, что и сам Perl.
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/Test