Тест
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- СИНТАКСИС
- ОПИСАНИЕ
- РУКОВОДСТВО ПО БЫСТРОМУ НАЧАЛУ
- ТИПЫ ТЕСТОВ
- ПРИ НЕУДАЧЕ
- ОШИБКИ И ОГРАНИЧЕНИЯ
- ОКРУЖЕНИЕ
- ПРИМЕЧАНИЕ
- СМОТРИТЕ ТАКЖЕ
- АВТОР
НАЗВАНИЕ
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 -
Ссылка на подпрограмму, которая должна быть выполнена в конце тестового скрипта, если какие-либо тесты провалились. См. "ПРИ НЕУДАЧЕ".
Вы должны вызвать
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", а второй и последний символы - одинаковый неалфавитный нечисловой неразрывный символ. Эти regexp
Примеры регулярных выражений:
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;Если какой-либо (или оба!) является ссылкой на подпрограмму, она выполняется, и ее возвращаемое значение используется в качестве реального значения этого параметра. Предположим, что
$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 начинает работать, он должен быть переведён в нормальный тест, а новая работающая функция должна быть задокументирована в примечаниях к релизу или в журнале изменений.
ПРИ НЕУДАЧЕ
BEGIN { plan test => 4, onfail => sub { warn "CALL 911!" } } Хотя провалы тестов должны быть достаточно информативными, дополнительные диагностические сведения могут быть активированы в конце выполнения теста. onfail получает массив ссылок на хэши, описывающие каждый провал теста. Каждый хэш будет содержать, по крайней мере, следующие поля: package, repetition, и result. (Вы не должны полагаться на наличие других полей.) Если у теста было ожидаемое значение или диагностическая (или "примечание") строка, они также будут включены.
Необязательный крючок onfail может использоваться просто для вывода версии вашего пакета и/или для способа сообщения о проблемах. Он также может использоваться для генерации чрезвычайно сложных диагностических данных для особенно странного провала теста. Однако он не является панацеей. Сбой ядра или другие необратимые ошибки предотвращают выполнение крючка onfail. (Он выполняется внутри блока END). Кроме того, onfail вероятно, избыточен в большинстве случаев. (Ваш тестовый код должен быть проще, чем код, который он тестирует, да?)
ОШИБКИ И ОГРАНИЧЕНИЯ
-
ok(...)'s special handling of strings which look like they might be regexes can also cause unexpected behavior. An innocent:ok( $fileglob, '/path/to/some/*stuff/' );will fail, since Test.pm considers the second argument to be a regex! The best bet is to use the one-argument form:
ok( $fileglob eq '/path/to/some/*stuff/' ); -
ok(...)'s use of stringeqcan sometimes cause odd problems when comparing numbers, especially if you're casting a string to a number:$foo = "1.0"; ok( $foo, 1 ); # not ok, "1.0" ne 1Your best bet is to use the single argument form:
ok( $foo == 1 ); # ok "1.0" == 1 -
As you may have inferred from the above documentation and examples,
ok's prototype is($;$$)(and, incidentally,skip's is($;$$$)). This means, for example, that you can dook @foo, @barto compare the size of the two arrays. But don't be fooled into thinking thatok @foo, @barmeans a comparison of the contents of two arrays -- you're comparing just the number of elements of each. It's so easy to make that mistake in readingok @foo, @barthat you might want to be very explicit about it, and instead writeok scalar(@foo), scalar(@bar). -
This almost definitely doesn't do what you expect:
ok $thingy->can('some_method');Why? Because
canreturns a coderef to mean "yes it can (and the method is this...)", and thenoksees a coderef and thinks you're passing a function that you want it to call and consider the truth of the result of! I.e., just like:ok $thingy->can('some_method')->();What you probably want instead is this:
ok $thingy->can('some_method') && 1;If the
canreturns false, then that is passed took. If it returns true, then the larger expression$thingy->can('some_method') && 1returns 1, whichoksees as a simple signal of success, as you would expect. -
The syntax for
skipis about the only way it can be, but it's still quite confusing. Just start with the above examples and you'll be okay.Moreover, users may expect this:
skip $unless_mswin, foo($bar), baz($quux);to not evaluate
foo($bar)andbaz($quux)when the test is being skipped. But in reality, they are evaluated, butskipjust won't bother comparing them if$unless_mswinis true.You could do this:
skip $unless_mswin, sub{foo($bar)}, sub{baz($quux)};But that's not terribly pretty. You may find it simpler or clearer in the long run to just do things like this:
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" } }But be quite sure that
okis called exactly as many times in the first block asskipis called in the second block.
Окружение
Если переменная среды 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 позволяет встраивать тесты в код.
АВТОР
Авторские права (c) 1998-2000 Joshua Nathaniel Pritikin.
Авторские права (c) 2001-2002 Michael G. Schwern.
Авторские права (c) 2002-2004 Sean M. Burke.
Текущий разработчик: Jesse Vincent. <jesse@bestpractical.com>
Этот пакет является свободным программным обеспечением и предоставляется «как есть» без явных или подразумеваемых гарантий. Его можно использовать, перераспределять и/или изменять на тех же условиях, что и Perl сам по себе.
© 1993–2023 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.38.0/Test