內容

名稱

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() 函式來執行任何操作,但它無法提供良好的診斷輸出。

當計畫順利進行時,我愛極了

在進行其他任何事之前,你需要一個測試計畫。這基本上宣告你的指令碼將執行多少測試以防止過早失敗。

執行此操作的首選方式是在使用 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 將匯出的函式,則必須使用「匯入」選項。例如,要匯入所有內容,但略過「失敗」,你可以執行

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' );

(助記符:「這沒問題。」)

$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 作為自己的小測試執行,並有自己的計畫和結果。主測試會將其視為單一測試,並使用整個子測試的結果來判斷是否正常或不正常。

例如...

 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()(宣告測試正常)或 fail(不正常)。它們是 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() 目前對於函式參考和 glob 的處理非常有限。它僅檢查它們是否具有相同的參照。這可能會在未來得到改善。

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(),但當測試在測試架構中執行時,訊息將不會顯示。它只會在詳細 TAP 串流中可見。

對於放置在註解中、可能有助於除錯但不會指出問題的訊息非常方便。

note("Tempfile is $tempfile");
explain
my @dump = explain @diagnostic_message;

會以人類可讀的格式傾印任何參照的內容。通常您會想要將此傳入 notediag

對於類似以下事項非常方便...

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 會輸出 Test::Harness 視為跳過但通過的特殊 ok。

$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" );
}

對於待辦區塊,預期裡面的測試會失敗。Test::More 會正常執行測試,但會列印出特殊標記,表示它們是「待辦」。Test::Harness 會將失敗解釋為正常。如果任何事情成功,它會將其報告為意外的成功。然後您會知道您待辦的事項已完成,並可以移除 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...
}

對於待辦測試,最好實際執行測試。這樣您就會知道它們何時開始通過。有時這是不可行的。通常,失敗的測試會導致整個程式死掉或當機,即使在使用 alarmeval BLOCK 內部也是如此。在這些極端情況下,您別無選擇,只能完全跳過損壞的測試。

語法和行為類似於 SKIP: BLOCK,但測試會標示為失敗但待辦。 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::More 底層的 Test::Builder 物件,供你使用。

EXIT CODE

如果你的所有測試都通過,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 可與 5.8.1 等舊版的 Perl 搭配使用。

在 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 是搭配 0.98 的 Perl 5.14.0。

done_testing()

這在 Test::More 0.88 中釋出,並在 Perl 5.10.1 中作為 Test::More 0.92 的一部分首次附帶發布。

cmp_ok()

儘管 cmp_ok() 在 0.40 中引入,但 0.86 修復了一個重要的錯誤,使其對超載物件安全;此修復在 Perl 5.10.1 中作為 Test::More 0.92 的一部分首次附帶發布。

new_ok() note()explain()

這些在 Test::More 0.82 中釋出,並在 Perl 5.10.1 中作為 Test::More 0.92 的一部分首次附帶發布。

在 Changes 檔案中有完整的版本記錄,而包含在核心中的 Test::More 版本可以使用 Module::CoreList 找到。

$ corelist -a Test::More

注意事項和說明

utf8 / 「列印中的寬字元」

如果您在 Test::More 中使用 utf8 或其他非 ASCII 字元,您可能會收到「列印中的寬字元」警告。使用 binmode STDOUT, ":utf8" 無法修復此問題。 Test::Builder(為 Test::More 提供支援)複製 STDOUT 和 STDERR。因此,對它們的任何變更,包括變更其輸出規則,Test::More 都看不到。

一種解決方法是在 Test::More(或任何其他 Test 模組)載入之前,盡早將編碼套用到 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 <schwern@pobox.com> 受到 Joshua Pritikin 的 Test 模組的許多啟發,以及 Barrie Slaymaker、Tony Bowden、blackstar.co.uk、chromatic、Fergal Daly 和 perl-qa 團隊的許多幫助。

維護人員

Chad Granum <exodist@cpan.org>

錯誤

請參閱 https://github.com/Test-More/test-more/issues 以報告和檢視錯誤。

原始碼

Test::More 的原始碼存放庫位於 http://github.com/Test-More/test-more/

版權

版權所有 2001-2008 Michael G Schwern <schwern@pobox.com>。

此程式為免費軟體;您可以在與 Perl 相同的條款下重新散布或修改它。

請參閱 http://www.perl.com/perl/misc/Artistic.html