Test::More - 另一个编写测试脚本的框架
use Test::More tests => 23;
# or
use Test::More skip_all => $reason;
# or
use Test::More; # see done_testing()
require_ok( 'Some::Module' );
# Various ways to say "ok"
ok($got eq $expected, $test_name);
is ($got, $expected, $test_name);
isnt($got, $expected, $test_name);
# Rather than print STDERR "# here's what went wrong\n"
diag("here's what went wrong");
like ($got, qr/expected/, $test_name);
unlike($got, qr/expected/, $test_name);
cmp_ok($got, '==', $expected, $test_name);
is_deeply($got_complex_structure, $expected_complex_structure, $test_name);
SKIP: {
skip $why, $how_many unless $have_some_feature;
ok( foo(), $test_name );
is( foo(42), 23, $test_name );
};
TODO: {
local $TODO = $why;
ok( foo(), $test_name );
is( foo(42), 23, $test_name );
};
can_ok($module, @methods);
isa_ok($object, $class);
pass($test_name);
fail($test_name);
BAIL_OUT($why);
# UNIMPLEMENTED!!!
my @status = Test::More::status;
停止! 如果你刚开始编写测试,先看看 Test2::Suite。
这是一个 Test::Simple 的替代品,一旦你掌握了基本的测试方法,就可以切换到它。
该模块的目的是提供广泛的测试实用程序。各种方法来表达“ok”,并提供更好的诊断信息,以及跳过测试、测试未来功能和比较复杂数据结构的功能。虽然你可以用简单的 ok()
函数完成几乎所有事情,但它没有提供良好的诊断输出。
在任何其他操作之前,您需要一个测试计划。这基本上声明了您的脚本将运行多少个测试以防止过早失败。
首选方法是在使用 use Test::More
时声明一个计划。
use Test::More tests => 23;
在某些情况下,您事先并不知道您的脚本将运行多少个测试。在这种情况下,您可以在最后声明您的测试。
use Test::More;
... run your tests ...
done_testing( $number_of_tests_run );
注意 done_testing()
永远不应该在 END { ... }
块中调用。
有时您真的不知道运行了多少个测试,或者计算起来太困难。在这种情况下,您可以省略 $number_of_tests_run。
在某些情况下,您可能希望完全跳过整个测试脚本。
use Test::More skip_all => $skip_reason;
您的脚本将声明一个跳过,并说明跳过的原因,并立即以零 (成功) 退出。有关详细信息,请参阅 Test::Harness。
如果您想控制 Test::More 将导出的函数,您必须使用“import”选项。例如,要导入除“fail”之外的所有内容,您可以执行以下操作
use Test::More tests => 23, import => ['!fail'];
或者,您可以使用 plan()
函数。当您必须计算测试数量时很有用。
use Test::More;
plan tests => keys %Stuff * 3;
或者用于决定是否运行测试
use Test::More;
if( $^O eq 'MacOS' ) {
plan skip_all => 'Test irrelevant on MacOS';
}
else {
plan tests => 42;
}
done_testing();
done_testing($number_of_tests);
如果您不知道要运行多少个测试,您可以在运行完测试后发布计划。
$number_of_tests 与 plan()
相同,它是您预期运行的测试数量。您可以省略它,在这种情况下,您运行的测试数量无关紧要,重要的是您的测试运行到结束。
这比“no_plan”计划更安全,并且取代了它。
注意:您永远不能将 done_testing()
放入 END { ... }
块中。该计划旨在确保您的测试在测试完成之前不会退出。如果您使用 END 块,您将完全绕过此保护。
按照惯例,每个测试都会按顺序分配一个编号。这在很大程度上是自动为您完成的。但是,为每个测试分配一个名称通常非常有用。您更愿意看到哪一个
ok 4
not ok 5
ok 6
或
ok 4 - basic multi-variable
not ok 5 - simple exponential
ok 6 - force == mass * acceleration
后者让你对失败的原因有所了解。它也让在你的脚本中找到测试变得更容易,只需搜索“简单指数”。
所有测试函数都接受一个名称参数。它是可选的,但强烈建议你使用它。
这个模块的基本目的是根据给定测试是否成功或失败,打印出“ok #”或“not ok #”。其他一切都是锦上添花。
以下所有内容都会根据测试是否成功或失败打印“ok”或“not ok”。它们也都分别返回 true 或 false。
ok($got eq $expected, $test_name);
这只是简单地评估任何表达式($got eq $expected
只是一个简单的例子),并使用它来确定测试是否成功或失败。真表达式通过,假表达式失败。非常简单。
例如
ok( $exp{9} == 81, 'simple exponential' );
ok( Film->can('db_Main'), 'set_db()' );
ok( $p->tests == 4, 'saw tests' );
ok( !grep(!defined $_, @items), 'all items defined' );
(助记符:“这是 ok 的。”)
$test_name
是对测试的非常简短的描述,它将被打印出来。它让在你的脚本中找到失败的测试变得非常容易,并让其他人了解你的意图。$test_name
是可选的,但我们非常强烈建议使用它。
如果 ok()
失败,它将产生一些诊断信息
not ok 18 - sufficient mucus
# Failed test 'sufficient mucus'
# in foo.t at line 42.
这与 Test::Simple 的 ok()
例程相同。
is ( $got, $expected, $test_name );
isnt( $got, $expected, $test_name );
与 ok()
类似,is()
和 isnt()
分别使用 eq
和 ne
比较它们的两个参数,并使用结果来确定测试是否成功或失败。所以这些
# Is the ultimate answer 42?
is( ultimate_answer(), 42, "Meaning of Life" );
# $foo isn't empty
isnt( $foo, '', "Got some foo" );
类似于这些
ok( ultimate_answer() eq 42, "Meaning of Life" );
ok( $foo ne '', "Got some foo" );
undef
永远只会匹配 undef
。所以你可以像这样测试一个值是否与 undef
相匹配
is($not_defined, undef, "undefined as expected");
(助记符:“这是那个。”“这不是那个。”)
那么为什么要使用这些呢?它们在失败时会产生更好的诊断信息。ok()
无法知道你在测试什么(除了名称),但 is()
和 isnt()
知道测试是什么以及为什么失败。例如,这个测试
my $foo = 'waffle'; my $bar = 'yarblokos';
is( $foo, $bar, 'Is foo the same as bar?' );
将产生类似于这样的内容
not ok 17 - Is foo the same as bar?
# Failed test 'Is foo the same as bar?'
# in foo.t at line 139.
# got: 'waffle'
# expected: 'yarblokos'
这样你就可以找出问题所在,而无需重新运行测试。
鼓励您尽可能使用is()
和isnt()
而不是ok()
,但是不要试图用它们来判断某件事是真还是假!
# XXX BAD!
is( exists $brooklyn{tree}, 1, 'A tree grows in Brooklyn' );
这不会检查exists $brooklyn{tree}
是否为真,它检查它是否返回1。两者大不相同。类似的警告也适用于false和0。在这些情况下,请使用ok()
。
ok( exists $brooklyn{tree}, 'A tree grows in Brooklyn' );
对isnt()
的简单调用通常不会提供强有力的测试,但有些情况下,除了它与其他值不同之外,你无法对一个值说更多。
new_ok $obj, "Foo";
my $clone = $obj->clone;
isa_ok $obj, "Foo", "Foo->clone";
isnt $obj, $clone, "clone() produces a different object";
历史上我们支持isn't()
函数作为isnt()
的别名,但在Perl 5.37.9中,使用撇号作为包分隔符的支持被弃用,在Perl 5.42.0中,对它的支持将被完全移除。因此,使用isn't()
也被弃用,并且在使用时会产生警告,除非在使用它的范围内明确禁用“已弃用”警告。强烈建议您迁移到使用isnt()
。
like( $got, qr/expected/, $test_name );
与ok()
类似,like()
将$got与正则表达式qr/expected/
匹配。
所以这个
like($got, qr/expected/, 'this is like that');
类似于
ok( $got =~ m/expected/, 'this is like that');
(助记符“This is like that”。)
第二个参数是一个正则表达式。它可以作为正则表达式引用(即qr//
)给出,也可以(为了与旧的perl更好地兼容)作为看起来像正则表达式的字符串给出(目前不支持替代分隔符)
like( $got, '/expected/', 'this is like that' );
正则表达式选项可以放在末尾('/expected/i'
)。
它相对于ok()
的优势类似于is()
和isnt()
。失败时更好的诊断信息。
unlike( $got, qr/expected/, $test_name );
与like()
的工作方式完全相同,只是它检查$got是否不匹配给定的模式。
cmp_ok( $got, $op, $expected, $test_name );
介于ok()
和is()
之间的是cmp_ok()
。这允许你使用任何二元perl运算符比较两个参数。如果比较结果为真,则测试通过,否则失败。
# ok( $got eq $expected );
cmp_ok( $got, 'eq', $expected, 'this eq that' );
# ok( $got == $expected );
cmp_ok( $got, '==', $expected, 'this == that' );
# ok( $got && $expected );
cmp_ok( $got, '&&', $expected, 'this && that' );
...etc...
它相对于ok()
的优势在于,当测试失败时,你会知道$got和$expected是什么。
not ok 1
# Failed test in foo.t at line 12.
# '23'
# &&
# undef
它在比较数字时也很有用,而is()
使用eq
会造成干扰。
cmp_ok( $big_hairy_number, '==', $another_big_hairy_number );
在比较值之间的大于或小于关系时,它特别有用。
cmp_ok( $some_value, '<=', $upper_limit );
can_ok($module, @methods);
can_ok($object, @methods);
检查以确保 $module 或 $object 可以执行这些 @methods(也适用于函数)。
can_ok('Foo', qw(this that whatever));
几乎等同于说
ok( Foo->can('this') &&
Foo->can('that') &&
Foo->can('whatever')
);
只是没有所有的类型,并且具有更好的接口。对于快速测试接口非常方便。
无论你检查多少个 @methods,一个 can_ok()
调用都算作一个测试。如果你希望结果不同,请使用
foreach my $meth (@methods) {
can_ok('Foo', $meth);
}
isa_ok($object, $class, $object_name);
isa_ok($subclass, $class, $object_name);
isa_ok($ref, $type, $ref_name);
检查给定的 $object->isa($class)
是否成立。还会检查对象是否在第一位定义。对于这种事情非常方便
my $obj = Some::Module->new;
isa_ok( $obj, 'Some::Module' );
否则你必须写
my $obj = Some::Module->new;
ok( defined $obj && $obj->isa('Some::Module') );
以防止你的测试脚本崩溃。
你也可以测试一个类,以确保它具有正确的祖先
isa_ok( 'Vole', 'Rodent' );
它也适用于引用
isa_ok( $array_ref, 'ARRAY' );
此测试的诊断通常只引用“对象”。如果你希望它们更具体,你可以提供一个 $object_name(例如“测试客户”)。
my $obj = new_ok( $class );
my $obj = new_ok( $class => \@args );
my $obj = new_ok( $class => \@args, $object_name );
一个便利函数,它将创建一个对象并调用该对象的 isa_ok()
函数结合起来。
它基本上等同于
my $obj = $class->new(@args);
isa_ok $obj, $class, $object_name;
如果未给出 @args,则将使用空列表。
此函数仅适用于 new()
,并且假设 new()
将仅返回一个 isa $class
的对象。
subtest $name => \&code, @args;
subtest()
将 &code 作为它自己的小型测试运行,并拥有自己的计划和结果。主测试将此视为一个测试,使用整个子测试的结果来确定它是 ok 还是 not ok。
例如...
use Test::More tests => 3;
pass("First test");
subtest 'An example subtest' => sub {
plan tests => 2;
pass("This is a subtest");
pass("So is this");
};
pass("Third test");
这将产生。
1..3
ok 1 - First test
# Subtest: An example subtest
1..2
ok 1 - This is a subtest
ok 2 - So is this
ok 2 - An example subtest
ok 3 - Third test
子测试可以调用 skip_all
。不会运行任何测试,但子测试被视为跳过。
subtest 'skippy' => sub {
plan skip_all => 'cuz I said so';
pass('this test will never be run');
};
如果子测试通过,则返回 true,否则返回 false。
由于子测试的工作方式,如果你愿意,可以省略计划。这将在你的子测试末尾添加一个隐式的 done_testing()
。以下两个子测试是等效的
subtest 'subtest with implicit done_testing()', sub {
ok 1, 'subtests with an implicit done testing should work';
ok 1, '... and support more than one test';
ok 1, '... no matter how many tests are run';
};
subtest 'subtest with explicit done_testing()', sub {
ok 1, 'subtests with an explicit done testing should work';
ok 1, '... and support more than one test';
ok 1, '... no matter how many tests are run';
done_testing();
};
传递给 subtest
的额外参数将传递给回调。例如
sub my_subtest {
my $range = shift;
...
}
for my $range (1, 10, 100, 1000) {
subtest "testing range $range", \&my_subtest, $range;
}
pass($test_name);
fail($test_name);
有时你只想说测试已经通过。通常情况下,你有一些复杂的条件,很难将其塞进 ok()
中。在这种情况下,你可以简单地使用 pass()
(声明测试 ok)或 fail(表示 not ok)。它们是 ok(1)
和 ok(0)
的同义词。
非常非常非常谨慎地使用它们。
有时你想测试一个模块或一组模块是否可以成功加载。例如,你通常希望第一个测试简单地加载分发中的所有模块,以确保它们在进行更复杂的测试之前正常工作。
为此,我们有 use_ok
和 require_ok
。
require_ok($module);
require_ok($file);
尝试使用 require
加载给定的 $module 或 $file。如果加载成功,测试将通过。否则测试失败并显示加载错误。
require_ok
会猜测输入是模块名称还是文件名。
如果加载失败,不会抛出异常。
# require Some::Module
require_ok "Some::Module";
# require "Some/File.pl";
require_ok "Some/File.pl";
# stop testing if any of your modules will not load
for my $module (@module) {
require_ok $module or BAIL_OUT "Can't load $module";
}
BEGIN { use_ok($module); }
BEGIN { use_ok($module, @imports); }
与 require_ok
相似,但它会 use
相关的 $module,并且只加载模块,不加载文件。
如果你只想测试模块是否可以加载,请使用 require_ok
。
如果你只想在测试中加载模块,我们建议直接使用 use
。它会导致测试停止。
建议在 BEGIN 块中运行 use_ok()
,以便其函数在编译时导出,并且原型得到正确处理。
如果提供了 @imports,它们将被传递给 use。所以这样
BEGIN { use_ok('Some::Module', qw(foo bar)) }
就像这样做
use Some::Module qw(foo bar);
版本号可以这样检查
# Just like "use Some::Module 1.02"
BEGIN { use_ok('Some::Module', 1.02) }
不要尝试这样做
BEGIN {
use_ok('Some::Module');
...some code that depends on the use...
...happening at compile time...
}
因为“编译时”的概念是相对的。相反,你需要
BEGIN { use_ok('Some::Module') }
BEGIN { ...some code that depends on the use... }
如果你想要 use Foo ()
的等效功能,请使用模块但不导入任何内容,使用 require_ok
。
BEGIN { require_ok "Foo" }
并非所有内容都是简单的 eq 检查或正则表达式。有时你需要查看两个数据结构是否等效。对于这些情况,Test::More 提供了一些有用的函数。
注意我不确定文件句柄会发生什么。
is_deeply( $got, $expected, $test_name );
类似于 is()
,除了如果 $got 和 $expected 是引用,它会进行深度比较,遍历每个数据结构以查看它们是否等效。如果两个结构不同,它将显示它们开始不同的位置。
is_deeply()
比较引用的解引用值,引用本身(除了它们的类型)被忽略。这意味着祝福和绑定等方面不被视为“不同”。
is_deeply()
目前对函数引用和全局变量的处理非常有限。它只是检查它们是否具有相同的引用。这在未来可能会改进。
Test::Differences 和 Test::Deep 提供了更多这方面的深入功能。
注意 is_deeply() 在比较字符串和引用时存在限制
my $path = path('.');
my $hash = {};
is_deeply( $path, "$path" ); # ok
is_deeply( $hash, "$hash" ); # fail
这是因为 `is_deeply` 会无条件地取消所有参数的重载。最好不要将 `is_deeply` 与重载一起使用。出于遗留原因,这不太可能被修复。如果您想要一个更好的工具,您应该查看 Test2::Suite,特别是 Test2::Tools::Compare 有一个 `is()` 函数,它像 `is_deeply` 一样工作,但有很多改进。
如果您选择了正确的测试函数,通常您会很好地了解测试失败的原因。但有时情况并非如此。因此,这里有一些方法可以编写您自己的诊断消息,这些消息比简单的 `print STDERR` 更安全。
diag(@diagnostic_message);
打印一条诊断消息,保证不会干扰测试输出。就像 `print` 一样,`@diagnostic_message` 只是简单地连接在一起。
返回 false,以保留失败。
对于以下情况非常有用
ok( grep(/foo/, @users), "There's a foo user" ) or
diag("Since there's no foo, check that /etc/bar is set up right");
这将产生
not ok 42 - There's a foo user
# Failed test 'There's a foo user'
# in foo.t at line 52.
# Since there's no foo, check that /etc/bar is set up right.
您可能还记得 `ok() or diag()`,其助记符为 `open() or die()`。
注意 诊断输出的精确格式仍在变化,但可以保证无论您输入什么,都不会干扰测试。
note(@diagnostic_message);
与 `diag()` 相似,只是当测试在 harness 中运行时,消息不会显示。它只会在详细的 TAP 流中可见。
对于添加可能对调试有用的注释非常有用,但并不表示存在问题。
note("Tempfile is $tempfile");
my @dump = explain @diagnostic_message;
将以人类可读的格式转储任何引用的内容。通常您希望将其传递给 `note` 或 `diag`。
对于以下情况非常有用...
is_deeply($have, $want) || diag explain $have;
或
note explain \%args;
Some::Class->method(%args);
有时在特定条件下运行测试会导致测试脚本崩溃。某些函数或方法未实现(例如 MacOS 上的 `fork()`),某些资源不可用(例如网络连接)或某些模块不可用。在这些情况下,有必要跳过测试,或声明它们应该失败,但将来会正常工作(待办事项测试)。
有关跳过和待办事项测试机制的更多详细信息,请参阅 Test::Harness。
Test::More 处理此问题的方式是使用命名块。基本上,这是一个可以跳过或设置为待办事项的测试块。最好直接向您展示...
SKIP: {
skip $why, $how_many if $condition;
...normal testing code goes here...
}
这声明了一个可能被跳过的测试块,`$how_many` 表示测试的数量,`$why` 表示跳过测试的原因,以及在什么 `$condition` 下跳过测试。示例是最简单的方式来说明
SKIP: {
eval { require HTML::Lint };
skip "HTML::Lint not installed", 2 if $@;
my $lint = new HTML::Lint;
isa_ok( $lint, "HTML::Lint" );
$lint->parse( $html );
is( $lint->errors, 0, "No errors found in HTML" );
}
如果用户没有安装 HTML::Lint,整个代码块将不会运行。Test::More 将输出特殊的 ok,Test::Harness 会将其解释为跳过,但通过测试。
重要的是 $how_many 准确地反映了 SKIP 块中的测试数量,这样运行的测试数量将与你的计划相符。如果你的计划是 no_plan
,$how_many 是可选的,并将默认设置为 1。
嵌套 SKIP 块是完全安全的。每个 SKIP 块必须有标签 SKIP
,否则 Test::More 无法发挥其作用。
你不应该跳过由于程序中的错误而失败的测试,或者你还没有编写代码的测试。为此,你使用 TODO。继续阅读。
TODO: {
local $TODO = $why if $condition;
...normal testing code goes here...
}
声明你期望失败的测试块和 $why。可能是因为你还没有修复错误或还没有完成新功能。
TODO: {
local $TODO = "URI::Geller not finished";
my $card = "Eight of clubs";
is( URI::Geller->your_card, $card, 'Is THIS your card?' );
my $spoon;
URI::Geller->bend_spoon;
is( $spoon, 'bent', "Spoon bending, that's original" );
}
使用 todo 块,块内的测试预计会失败。Test::More 将正常运行测试,但会打印出特殊的标志,表明它们是“todo”。Test::Harness 将把失败解释为正常。如果任何测试成功,它将报告为意外成功。然后你就知道你应该做的事情已经完成,可以删除 TODO 标志。
todo 测试的优点,与简单地注释掉测试块相比,它就像有一个程序化的 todo 列表。你知道还有多少工作要做,你知道有哪些错误,并且你将立即知道它们何时被修复。
一旦 todo 测试开始成功,只需将其移出块。当块为空时,将其删除。
请注意,如果你将 $TODO 设置为未设置或未定义,Test::More 会将失败报告为正常。这在某些情况下很有用,例如,你希望将测试标记为仅在特定条件下预计会失败。
TODO: {
local $TODO = "$^O doesn't work yet. :(" if !_os_is_supported($^O);
...
}
TODO: {
todo_skip $why, $how_many if $condition;
...normal testing code...
}
对于 todo 测试,最好让测试实际运行。这样你就会知道它们何时开始通过。有时这是不可能的。通常,失败的测试会导致整个程序死亡或挂起,即使在 eval BLOCK
内使用 alarm
也是如此。在这些极端情况下,你只能选择完全跳过损坏的测试。
语法和行为类似于 SKIP: BLOCK
,只是测试将被标记为失败但 todo。 Test::Harness 将将其解释为通过。
如果这是用户可能无法做的事情,请使用 SKIP。这包括未安装的可选模块,在没有某些功能(如 fork()
或符号链接)的操作系统下运行,或者可能你需要互联网连接,但没有可用连接。
如果程序员还没有完成某些工作,请使用 TODO。这适用于您尚未编写的任何代码,或您尚未修复的错误,但希望在测试脚本中添加测试(始终是一个好主意)。
BAIL_OUT($reason);
指示测试框架所有测试都应该终止,因为情况非常糟糕。这包括运行任何其他测试脚本。
这通常用于测试无法继续进行的情况下,例如关键模块无法编译或必要的外部实用程序不可用,例如数据库连接失败。
测试将退出并返回 255。
为了获得更好的控制,请查看 Test::Most。
不鼓励使用以下函数,因为它们实际上不是测试函数,并且不会生成任何诊断信息来帮助找出问题所在。它们是在 is_deeply()
存在之前编写的,因为我无法弄清楚如何显示两个任意数据结构的有用差异。
这些函数通常在 ok()
中使用。
ok( eq_array(\@got, \@expected) );
is_deeply()
可以更好地做到这一点,并提供诊断信息。
is_deeply( \@got, \@expected );
它们可能会在将来的版本中被弃用。
my $is_eq = eq_array(\@got, \@expected);
检查两个数组是否等效。这是一个深度检查,因此多级结构将被正确处理。
my $is_eq = eq_hash(\%got, \%expected);
确定两个哈希是否包含相同的键和值。这是一个深度检查。
my $is_eq = eq_set(\@got, \@expected);
类似于 eq_array()
,但元素的顺序不重要。这是一个深度检查,但顺序无关性仅适用于顶层。
ok( eq_set(\@got, \@expected) );
最好写成
is_deeply( [sort @got], [sort @expected] );
注意 由于历史原因,这不是真正的集合比较。虽然元素的顺序无关紧要,但重复元素很重要。
注意 eq_set()
不知道如何处理顶层的引用。以下是一个可能无法正常工作的比较示例
eq_set([\1, \2], [\2, \1]);
Test::Deep 包含更好的集合比较函数。
有时 Test::More 接口不够用。幸运的是,Test::More 建立在 Test::Builder 之上,它为任何测试库提供了一个统一的后端。这意味着两个都使用 Test::Builder 的测试库可以在同一个程序中一起使用。
如果您只是想稍微调整测试的行为,您可以访问底层的 Test::Builder 对象,如下所示
my $test_builder = Test::More->builder;
返回 Test::Builder 对象,该对象是 Test::More 的基础,供您使用。
如果所有测试都通过,Test::Builder 将以零退出(这是正常的)。如果任何测试失败,它将以失败的测试数量退出。如果您运行的测试少于(或多于)计划的测试,则缺少的(或额外的)测试将被视为失败。如果从未运行过任何测试,Test::Builder 将发出警告并以 255 退出。如果测试在成功完成所有测试后死亡,它仍然会被视为失败,并将以 255 退出。
因此,退出代码是...
0 all tests successful
255 test died or all passed but wrong # of tests run
any other number how many failed (including missing or extras)
如果您失败的测试超过 254 个,它将被报告为 254。
注意 此行为可能会在将来的版本中消失。
Test::More 与 Perl 5.8.1 及更早版本兼容。
在 5.10.1 之前,线程支持并不十分可靠,但这是因为在 5.10.1 之前,线程本身并不十分可靠。
尽管 Test::More 自 Perl 5.6.2 版本以来一直是核心模块,但 Test::More 自那时以来一直在发展,并且您习惯使用的一些功能可能不会出现在附带的 Test::More 版本中。如果您正在编写模块,请不要忘记在您的包元数据中指示您需要的 Test::More 的最低版本。例如,如果您想使用 done_testing()
但希望您的测试脚本在 Perl 5.10.0 上运行,您需要显式地要求 Test::More > 0.88。
关键功能里程碑包括
子测试在 Test::More 0.94 中发布,该版本随 Perl 5.12.0 一起发布。子测试直到 0.96 才隐式调用 done_testing()
;第一个包含此修复的 Perl 是 Perl 5.14.0,其中包含 0.98。
done_testing()
它在 Test::More 0.88 中发布,并首次作为 Test::More 0.92 的一部分随 Perl 5.10.1 一起发布。
cmp_ok()
虽然 cmp_ok()
在 0.40 中引入,但 0.86 修复了一个重要的错误,使其对重载对象安全;该修复首次作为 Test::More 0.92 的一部分随 Perl 5.10.1 一起发布。
new_ok()
note()
和 explain()
它们在 Test::More 0.82 中发布,并首次作为 Test::More 0.92 的一部分随 Perl 5.10.1 一起发布。
Changes 文件中包含完整的版本历史记录,并且可以使用 Module::CoreList 找到作为核心包含的 Test::More 版本。
$ corelist -a Test::More
如果您在 Test::More 中使用 utf8 或其他非 ASCII 字符,您可能会收到 "打印中出现宽字符" 的警告。使用 binmode STDOUT, ":utf8"
无法解决此问题。 Test::Builder(为 Test::More 提供支持)复制了 STDOUT 和 STDERR。因此,对它们的任何更改,包括更改它们的输出规则,都不会被 Test::More 看到。
一种解决方法是在尽可能早的阶段,并在 Test::More(或任何其他测试模块)加载之前,对 STDOUT 和 STDERR 应用编码。
use open ':std', ':encoding(utf8)';
use Test::More;
更直接的解决方法是更改 Test::Builder 使用的文件句柄。
my $builder = Test::More->builder;
binmode $builder->output, ":encoding(utf8)";
binmode $builder->failure_output, ":encoding(utf8)";
binmode $builder->todo_output, ":encoding(utf8)";
字符串重载对象被作为字符串比较(或者在 cmp_ok()
的情况下,根据比较操作符,适当的字符串或数字)。这阻止了 Test::More 穿透对象的接口,从而允许更好的黑盒测试。因此,如果一个函数开始返回重载对象而不是裸字符串,你的测试将不会注意到区别。这是好事。
但是,这意味着像 is_deeply()
这样的函数不能用于测试字符串重载对象的内部结构。在这种情况下,我建议使用 Test::Deep,它包含更灵活的测试函数,用于测试复杂的数据结构。
只有在 在 加载 Test::More 之前执行了 use threads
时,Test::More 才会意识到线程。这是可以的。
use threads;
use Test::More;
这可能会导致问题。
use Test::More
use threads;
支持 5.8.1 及更高版本。低于该版本的版本存在太多错误。
这是与 Joshua Pritikin 的 Test 模块的趋同演化的一个例子。当我第一次编写自己的 ok()
例程时,我基本上不知道它的存在。这个模块的存在是因为我无法弄清楚如何轻松地将测试名称插入 Test 的接口(以及其他一些问题)。
这里的目标是拥有一个易于学习、快速使用且难以出错的测试工具,同时提供比现有的 Test.pm 更大的灵活性。因此,最常用例程的名称保持简短,特殊情况和神奇的副作用被降至最低。所见即所得。
Test2::Suite 是最新和最现代的测试工具集。
Test::Simple 如果所有这些让你感到困惑,你只想编写一些测试。你以后可以升级到 Test::More(它向前兼容)。
Test::Legacy 使用 Test.pm(原始测试模块)编写的测试与其他测试库不兼容。Test::Legacy 模拟 Test.pm 接口,并且与其他库兼容。
Test::Differences 提供更多方法来测试复杂的数据结构。它与 Test::More 兼容。
Test::Class 类似于 xUnit,但更符合 Perl 风格。
Test::Deep 提供更强大的复杂数据结构测试功能。
Test::Inline 展示了嵌入式测试的概念。
Mock::Quick 最终的模拟库。轻松生成动态定义的对象。还可以根据需要覆盖、阻止或重新实现包。
Test::FixtureBuilder 快速定义单元测试的固定数据。
Test::Harness 是 Perl 的测试运行器和输出解释器。它是 make test
的驱动程序,也是 prove
工具的来源。
Test::Most 最常用的测试函数和功能。
Michael G Schwern <[email protected]>,在 Joshua Pritikin 的 Test 模块的启发下,并得到了 Barrie Slaymaker、Tony Bowden、blackstar.co.uk、chromatic、Fergal Daly 和 perl-qa 团队的大力帮助。
请访问 https://github.com/Test-More/test-more/issues 报告和查看错误。
Test::More 的源代码仓库位于 http://github.com/Test-More/test-more/。
版权所有 2001-2008 Michael G Schwern <[email protected]>。
本程序是自由软件;您可以在 Perl 本身相同的条款下重新发布和/或修改它。
请参阅 https://perldotcom.perl5.cn/perl/misc/Artistic.html