内容

名称

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();
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
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::Simpleok() 例程相同。

is
isnt
is  ( $got, $expected, $test_name );
isnt( $got, $expected, $test_name );

ok() 类似,is()isnt() 分别使用 eqne 比较它们的两个参数,并使用结果来确定测试是否成功或失败。所以这些

# 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
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
unlike( $got, qr/expected/, $test_name );

like()的工作方式完全相同,只是它检查$got是否匹配给定的模式。

cmp_ok
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
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
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(例如“测试客户”)。

new_ok
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
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
fail
pass($test_name);
fail($test_name);

有时你只想说测试已经通过。通常情况下,你有一些复杂的条件,很难将其塞进 ok() 中。在这种情况下,你可以简单地使用 pass()(声明测试 ok)或 fail(表示 not ok)。它们是 ok(1)ok(0) 的同义词。

非常非常非常谨慎地使用它们。

模块测试

有时你想测试一个模块或一组模块是否可以成功加载。例如,你通常希望第一个测试简单地加载分发中的所有模块,以确保它们在进行更复杂的测试之前正常工作。

为此,我们有 use_okrequire_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";
}
use_ok
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
is_deeply( $got, $expected, $test_name );

类似于 is(),除了如果 $got 和 $expected 是引用,它会进行深度比较,遍历每个数据结构以查看它们是否等效。如果两个结构不同,它将显示它们开始不同的位置。

is_deeply() 比较引用的解引用值,引用本身(除了它们的类型)被忽略。这意味着祝福和绑定等方面不被视为“不同”。

is_deeply() 目前对函数引用和全局变量的处理非常有限。它只是检查它们是否具有相同的引用。这在未来可能会改进。

Test::DifferencesTest::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
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
note(@diagnostic_message);

与 `diag()` 相似,只是当测试在 harness 中运行时,消息不会显示。它只会在详细的 TAP 流中可见。

对于添加可能对调试有用的注释非常有用,但并不表示存在问题。

note("Tempfile is $tempfile");
explain
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: BLOCK
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: BLOCK
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_skip
TODO: {
    todo_skip $why, $how_many if $condition;

    ...normal testing code...
}

对于 todo 测试,最好让测试实际运行。这样你就会知道它们何时开始通过。有时这是不可能的。通常,失败的测试会导致整个程序死亡或挂起,即使在 eval BLOCK 内使用 alarm 也是如此。在这些极端情况下,你只能选择完全跳过损坏的测试。

语法和行为类似于 SKIP: BLOCK,只是测试将被标记为失败但 todo。 Test::Harness 将将其解释为通过。

何时使用 SKIP 与 TODO?

如果这是用户可能无法做的事情,请使用 SKIP。这包括未安装的可选模块,在没有某些功能(如 fork() 或符号链接)的操作系统下运行,或者可能你需要互联网连接,但没有可用连接。

如果程序员还没有完成某些工作,请使用 TODO。这适用于您尚未编写的任何代码,或您尚未修复的错误,但希望在测试脚本中添加测试(始终是一个好主意)。

测试控制

BAIL_OUT
BAIL_OUT($reason);

指示测试框架所有测试都应该终止,因为情况非常糟糕。这包括运行任何其他测试脚本。

这通常用于测试无法继续进行的情况下,例如关键模块无法编译或必要的外部实用程序不可用,例如数据库连接失败。

测试将退出并返回 255。

为了获得更好的控制,请查看 Test::Most

不推荐的比较函数

不鼓励使用以下函数,因为它们实际上不是测试函数,并且不会生成任何诊断信息来帮助找出问题所在。它们是在 is_deeply() 存在之前编写的,因为我无法弄清楚如何显示两个任意数据结构的有用差异。

这些函数通常在 ok() 中使用。

ok( eq_array(\@got, \@expected) );

is_deeply() 可以更好地做到这一点,并提供诊断信息。

is_deeply( \@got, \@expected );

它们可能会在将来的版本中被弃用。

eq_array
my $is_eq = eq_array(\@got, \@expected);

检查两个数组是否等效。这是一个深度检查,因此多级结构将被正确处理。

eq_hash
my $is_eq = eq_hash(\%got, \%expected);

确定两个哈希是否包含相同的键和值。这是一个深度检查。

eq_set
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::More 建立在 Test::Builder 之上,它为任何测试库提供了一个统一的后端。这意味着两个都使用 Test::Builder 的测试库可以在同一个程序中一起使用。

如果您只是想稍微调整测试的行为,您可以访问底层的 Test::Builder 对象,如下所示

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

注意事项和说明

utf8 / "打印中出现宽字符"

如果您在 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 团队的大力帮助。

维护者

Chad Granum <[email protected]>

错误

请访问 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