Тест
СОДЕРЖАНИЕ
- ИМЯ
- СИНОПСИС
- ОПИСАНИЕ
- РУКОВОДСТВО ПО БЫСТРОМУ НАЧАЛУ
- ТИПЫ ТЕСТОВ
- ПРИ НЕУДАЧЕ
- ОШИБКИ И ОСОБЕННОСТИ
- СРЕДА
- ПРИМЕЧАНИЕ
- СМОТРИ ТАКЖЕ
- АВТОР
ИМЯ
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 TESTS".
-
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. Как только тест TODO начинает работать, он должен быть преобразован в нормальный тест, а новая работающая функция должна быть задокументирована в примечаниях к выпуску или в журнале изменений.
ПРИ НЕУДАЧЕ
BEGIN { plan test => 4, onfail => sub { warn "CALL 911!" } } Хотя провалы тестов должны быть достаточны, дополнительные диагностики могут быть инициированы в конце выполнения теста. onfail получает ссылку на массив, содержащий ссылки на структуры данных, описывающие каждый провал теста. Каждая структура данных будет содержать, по меньшей мере, следующие поля: package, repetition, и result. (Вы не должны полагаться на наличие других полей.) Если тест имел ожидаемое значение или диагностическую (или «примечание») строку, они также будут включены.
Необязаемый крючок onfail может использоваться просто для вывода версии вашего пакета и/или способа отчётности о проблемах. Он также может использоваться для генерации чрезвычайно сложных диагностик для особенно странного провала теста. Однако это не панацея. Ошибки core dump или другие необратимые ошибки препятствуют выполнению крючка onfail. (Он выполняется внутри блока END) Кроме того, onfail — вероятно, избыточно в большинстве случаев. (Ваш тестовый код должен быть проще, чем код, который он тестирует, да?)
ОШИБКИ И ОСОБЕННОСТИ
-
ok(...)'s special handing 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 позволяет встраивать тесты в код.
АВТОР
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–2020 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.32.0/Test