內容

名稱

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.tt/bar.tt/baz.t

函式

此模組定義了三個公用函式,plan(...)ok(...)skip(...)。預設情況下,這三個函式都由 use Test; 陳述式匯出。

plan(...)
BEGIN { plan %theplan; }

這應該是您在測試指令碼中呼叫的第一個函式。它宣告您的測試計畫,將會有多少個測試,是否允許其中任何一個測試失敗,等等。

典型的用法如下

use Test;
BEGIN { plan tests => 23 }

以下是您可以在 plan 參數中放入的內容

tests => 數字

指令碼中的測試數。這表示所有 ok() 和 skip() 呼叫。

todo => [1,5,14]

允許失敗的測試清單的參考。請參閱 "TODO TESTS"

onfail => 子常式 { ... }
onfail => \&some_sub

如果任何測試失敗,則在測試指令碼結束時執行的子常式參考。請參閱 "ONFAIL"

您必須呼叫 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(...) 僅接受單一純量表達式。如果其值為 true,則測試通過;如果為 false,則測試失敗。範例

# 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 語法中)。在這種情況下,它會被執行,其值(true 或 false)決定測試是否通過或失敗。例如,

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

如果第二個引數是正規表示式物件或看起來像正規表示式的字串,則會將其視為正規表示式。正規表示式物件使用 perl 最近版本的 qr// 算子建構。如果字串的第一個和最後一個字元是「/」,或者如果第一個字元是「m」,而其第二個和最後一個字元都是相同的非字母數字非空白字元,則會將字串視為看起來像正規表示式。這些正規表示式

正規表示式範例

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;

如果任一(或兩者!)是子常式參考,則會執行它並將其用作比較的值。例如

ok sub {
    open(OUT, '>', 'x.dat') || die $!;
    print OUT "\x{e000}";
    close OUT;
    my $bytecount = -s 'x.dat';
    unlink 'x.dat' or warn "Can't unlink : $!";
    return $bytecount;
  },
  4
;

上述測試將兩個值傳遞給 ok(arg1, arg2) -- 第一個是 coderef,第二個是數字 4。在 ok 比較它們之前,它會呼叫 coderef,並使用其回傳值作為此參數的實際值。假設 $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 -- 這並非您想要的!

上述所有特殊情況偶爾會造成一些問題。請參閱 "BUGS and CAVEATS"

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

測試類型

ONFAIL

BEGIN { plan test => 4, onfail => sub { warn "CALL 911!" } }

儘管測試失敗就足夠了,但在測試執行結束時可以觸發額外的診斷。onfail 傳遞一個雜湊參考陣列,其中描述每個測試失敗。每個雜湊至少包含下列欄位:packagerepetitionresult。(你不應依賴任何其他欄位。)如果測試有預期值或診斷(或「註解」)字串,也會包含這些值。

選用的 onfail 鉤子可以用來列印套件版本和/或如何報告問題。它也可以用來為特別奇怪的測試失敗產生極其複雜的診斷。然而,它並非萬靈丹。核心傾印或其他無法復原的錯誤會阻止 onfail 鉤子執行。(它在 END 區塊內執行。)此外,在多數情況下,onfail 可能過於強大。(你的測試程式碼應該比它所測試的程式碼更簡單,對吧?)

BUG 和注意事項

環境

如果設定了 PERL_TEST_DIFF 環境變數,它將被用作比較意外的多行結果的指令。如果您已安裝 GNU diff,您可能想將 PERL_TEST_DIFF 設定為 diff -u。如果您沒有合適的程式,您可能會安裝 Text::Diff 模組,然後將 PERL_TEST_DIFF 設定為 perl -MText::Diff -e 'print diff(@ARGV)'。如果未設定 PERL_TEST_DIFFAlgorithm::Diff 模組可用,則會使用它來顯示多行結果中的差異。

注意

此模組的過去開發人員曾說過,它不再被積極開發。然而,關於它消亡的謠言被大大誇大了。非常歡迎回饋和建議。

請注意,此模組的主要價值在於其簡單性。請注意,已經有更具野心的模組,例如 Test::MoreTest::Unit

此模組的一些早期版本的文件在 skip(...) 的說明中有一些令人困惑的錯字。

另請參閱

Test::Harness

Test::SimpleTest::MoreDevel::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 相同的條款使用、重新分發和/或修改。