內容

名稱

Test::Builder - 測試函式庫建置後端

語法

package My::Test::Module;
use base 'Test::Builder::Module';

my $CLASS = __PACKAGE__;

sub ok {
    my($test, $name) = @_;
    my $tb = $CLASS->builder;

    $tb->ok($test, $name);
}

說明

Test::SimpleTest::More 已證明是熱門的測試模組,但它們並不總是足夠靈活。Test::Builder 提供一個建構區塊,您可以在其上撰寫自己的測試函式庫,這些函式庫可以一起使用

建構

new
my $Test = Test::Builder->new;

傳回表示測試目前狀態的 Test::Builder 物件。

由於您只執行每個程式一個測試,因此 new 始終傳回相同的 Test::Builder 物件。不論您呼叫 new() 多少次,您都將取得相同的物件。這稱為單例。這樣做是為了讓多個模組共用全域資訊,例如測試計數器和測試輸出位置。

如果您想要一個與單例不同的全新 Test::Builder 物件,請使用 create

create
my $Test = Test::Builder->create;

好的,因此可以有多個 Test::Builder 物件,而這就是取得它的方式。如果您要測試基於 Test::Builder 的模組,您可以使用這個方法取代 new(),但否則您可能需要 new

注意:實作尚未完成。例如,level 仍由所有 Test::Builder 物件共用,即使是使用此方法建立的物件也是如此。此外,方法名稱可能會在未來變更。

subtest
$builder->subtest($name, \&subtests, @args);

請參閱 Test::More 中 subtest 的文件。

subtest 也會接受引數(這是選用的),這些引數會傳遞給子測試參考。

name
diag $builder->name;

傳回目前建構器的名稱。頂層建構器的預設值為 $0(可執行檔的名稱)。子建構器會透過 child 方法命名。如果未提供名稱,將命名為「$parent->name 的子項」。

重設
$Test->reset;

將 Test::Builder 單例重新初始化為其原始狀態。對於在持續環境中執行的測試,在同一個程序中可能多次執行相同的測試,因此非常有用。

設定測試

這些方法用於設定測試並宣告測試數量。您通常只會想要呼叫其中一個方法。

計畫
$Test->plan('no_plan');
$Test->plan( skip_all => $reason );
$Test->plan( tests => $num_tests );

設定測試的便利方法。呼叫此方法,Test::Builder 將列印適當的標頭並採取適當的動作。

如果您呼叫 plan(),請勿呼叫以下任何其他方法。

預期測試
my $max = $Test->expected_tests;
$Test->expected_tests($max);

取得/設定我們預期此測試執行的測試數量,並列印出適當的標頭。

無計畫
$Test->no_plan;

宣告此測試將執行不確定的測試數量。

完成測試
$Test->done_testing();
$Test->done_testing($num_tests);

宣告您已完成測試,在此點之後將不會再執行任何測試。

如果尚未輸出計畫,它將執行此動作。

$num_tests 是您計畫執行的測試數量。如果已宣告編號計畫,且與此相矛盾,將執行失敗測試以反映計畫錯誤。如果宣告 no_plan,這將覆寫。

如果呼叫 done_testing() 兩次,第二次呼叫將發出失敗測試。

如果省略 $num_tests,將使用執行的測試數量,例如 no_plan。

done_testing() 實際上是在您想要使用 no_plan 時使用,但更安全。您會像這樣使用它

$Test->ok($a == $b);
$Test->done_testing();

或計畫變數測試數量

for my $test (@tests) {
    $Test->ok($test);
}
$Test->done_testing(scalar @tests);
有計畫
$plan = $Test->has_plan

找出是否已定義計畫。$planundef(未設定計畫)、no_plan(不確定測試數量)或整數(預期測試數量)。

全部略過
$Test->skip_all;
$Test->skip_all($reason);

使用給定的 $reason 略過所有測試。立即以 0 退出。

匯出至
my $pack = $Test->exported_to;
$Test->exported_to($pack);

告訴 Test::Builder 您將函式匯出至哪個套件。

此方法並非非常有用,因為共用相同 Test::Builder 物件的模組可能會匯出至不同的套件,而只有最後一個套件會受到重視。

執行測試

這些實際執行測試,類似於 Test::More 中的函式。

如果測試通過,它們全部傳回 true,如果測試失敗,則傳回 false。

$name 永遠是選用的。

ok
$Test->ok($test, $name);

您的基本測試。如果 $test 為 true,則通過,如果 $test 為 false,則失敗。就像 Test::Simple 的 ok()

is_eq
$Test->is_eq($got, $expected, $name);

就像 Test::More 的 is()。檢查 $got eq $expected。這是字串版本。

undef 僅與另一個 undef 相符。

is_num
$Test->is_num($got, $expected, $name);

就像 Test::More 的 is()。檢查 $got == $expected。這是數字版本。

undef 僅與另一個 undef 相符。

isnt_eq
$Test->isnt_eq($got, $dont_expect, $name);

就像 Test::Moreisnt()。檢查 $got ne $dont_expect。這是字串版本。

isnt_num
$Test->isnt_num($got, $dont_expect, $name);

就像 Test::Moreisnt()。檢查 $got ne $dont_expect。這是數字版本。

like
$Test->like($thing, qr/$regex/, $name);
$Test->like($thing, '/$regex/', $name);

就像 Test::Morelike()。檢查 $thing 是否與給定的 $regex 相符。

unlike
$Test->unlike($thing, qr/$regex/, $name);
$Test->unlike($thing, '/$regex/', $name);

就像 Test::Moreunlike()。檢查 $thing 不與給定的 $regex 相符。

cmp_ok
$Test->cmp_ok($thing, $type, $that, $name);

就像 Test::Morecmp_ok() 一樣。

$Test->cmp_ok($big_num, '!=', $other_big_num);

其他測試方法

這些方法用於撰寫測試,但本身並非測試。

BAIL_OUT
$Test->BAIL_OUT($reason);

Test::Harness 指出情況非常糟糕,所有測試都應終止。這包括執行任何其他測試腳本。

它將以 255 退出。

skip
$Test->skip;
$Test->skip($why);

略過目前的測試,報告 $why

todo_skip
$Test->todo_skip;
$Test->todo_skip($why);

就像 skip(),只不過它會宣告測試失敗且為待辦事項。類似於

print "not ok $tnum # TODO $why\n";

測試建立實用方法

撰寫自己的測試方法時,這些方法很有用。

maybe_regex
$Test->maybe_regex(qr/$regex/);
$Test->maybe_regex('/$regex/');

當 Test::Builder 在 5.6 之前的 Perl 上執行時,這個方法很有用,因為當時沒有 qr//。現在它幾乎沒什麼用。

建立測試函數的便利方法,將正規表示式作為引數。

採用由 qr// 產生的正規表示式引號,或表示正規表示式的字串。

傳回 Perl 值,可以用來取代對應的正規表示式,或如果其引數無法辨識,則傳回 undef

例如,like() 的版本,沒有有用的診斷訊息,可以寫成

sub laconic_like {
    my ($self, $thing, $regex, $name) = @_;
    my $usable_regex = $self->maybe_regex($regex);
    die "expecting regex, found '$regex'\n"
        unless $usable_regex;
    $self->ok($thing =~ m/$usable_regex/, $name);
}
is_fh
my $is_fh = $Test->is_fh($thing);

判斷指定的 $thing 是否可用作檔案控制代碼。

測試樣式

level
$Test->level($how_high);

當報告測試失敗時,$Test 應該往上追溯呼叫堆疊多遠。

預設為 1。

設定 $Test::Builder::Level 會覆寫。這通常在區域化時很有用

sub my_ok {
    my $test = shift;

    local $Test::Builder::Level = $Test::Builder::Level + 1;
    $TB->ok($test);
}

為了對包裝您自己的其他函數有禮貌,您通常會想要增加 $Level,而不是將它設定為常數。

use_numbers
$Test->use_numbers($on_or_off);

測試是否應該輸出數字。也就是說,如果為真

ok 1
ok 2
ok 3

或如果為假

ok
ok
ok

當您無法依賴測試輸出順序時,這最有用,例如涉及執行緒或分岔時。

預設為開啟。

no_diag
$Test->no_diag($no_diag);

如果設定為真,則不會印出任何診斷。這包括對 diag() 的呼叫。

no_ending
$Test->no_ending($no_ending);

通常,Test::Builder 在測試結束時會執行一些額外的診斷。它也會變更退出代碼,如下所述。

如果這是真的,則不會執行任何這些操作。

no_header
$Test->no_header($no_header);

如果設定為 true,則不會列印「1..N」標頭。

輸出

控制測試輸出位置。

您的測試可以變更 STDOUT 和 STDERR 指向的位置,Test::Builder 的預設輸出設定不會受到影響。

diag
$Test->diag(@msgs);

列印指定的 @msgs。與 print 一樣,參數會直接附加在一起。

通常,它會使用 failure_output() 處理常式,但如果這是 TODO 測試,則會使用 todo_output() 處理常式。

輸出會縮排並標記為 #,以避免干擾測試輸出。如果最後沒有換行,則會在最後加上換行。

我們建議使用這個,而不是直接呼叫 print。

傳回 false。為什麼?因為 diag() 通常與失敗的測試一起使用 (ok() || diag()),它會「傳遞」失敗。

return ok(...) || diag(...);
note
$Test->note(@msgs);

diag() 類似,但它會列印至 output() 處理常式,因此使用者通常不會看到它,除非是在詳細模式下。

explain
my @dump = $Test->explain(@msgs);

會以人類可讀的格式傾印任何參考的內容。對於像...之類的東西來說很方便

is_deeply($have, $want) || diag explain $have;

is_deeply($have, $want) || note explain $have;
output
failure_output
todo_output
my $filehandle = $Test->output;
$Test->output($filehandle);
$Test->output($filename);
$Test->output(\$scalar);

這些方法控制 Test::Builder 將列印其輸出的位置。它們會取得一個開啟的 $filehandle、一個要開啟並寫入的 $filename 或一個要附加的 $scalar 參照。它將永遠傳回一個 $filehandle

output 是正常「ok/not ok」測試輸出的位置。

預設為 STDOUT。

failure_output 是測試失敗和 diag() 的診斷輸出的位置。它通常不會由 Test::Harness 讀取,而是顯示給使用者。

預設為 STDERR。

todo_output 用於失敗的 TODO 測試的診斷,而不是 failure_output()。使用者不會看到這些。

預設為 STDOUT。

reset_outputs
$tb->reset_outputs;

將所有輸出檔案控制碼重設回其預設值。

carp
$tb->carp(@message);

使用 @message 警告,但訊息會顯示為來自原始測試函式被呼叫的點 ($tb->caller)。

croak
$tb->croak(@message);

使用 @message 死亡,但訊息會顯示為來自原始測試函式被呼叫的點 ($tb->caller)。

測試狀態和資訊

no_log_results

這將關閉結果長期儲存。呼叫此方法會使 detailssummary 無用。如果你執行的測試足夠多,以填滿所有可用記憶體,你可能想使用這個方法。

Test::Builder->new->no_log_results();

沒有辦法重新開啟它。

current_test
my $curr_test = $Test->current_test;
$Test->current_test($num);

取得/設定我們目前進行的測試編號。您通常不必設定這個。

如果設定為前進,遺失測試的詳細資料會填入為「未知」。如果設定為後退,介入測試的詳細資料會刪除。如果您真的想要的話,可以清除歷史記錄。

is_passing
my $ok = $builder->is_passing;

指出測試套件目前是否通過。

更正式地說,如果發生任何讓測試套件無法通過的事情,它將為 false。否則為 true。

例如,如果沒有執行任何測試,is_passing() 將為 true,因為即使沒有測試的套件會失敗,您也可以新增通過的測試並開始通過。

不要想太多。

summary
my @tests = $Test->summary;

到目前為止的測試的簡單摘要。通過為 true,失敗為 false。這是一個邏輯上的通過/失敗,因此待辦事項是通過。

當然,測試 #1 是 $tests[0],等等...

details
my @tests = $Test->details;

類似於 summary(),但有更多詳細資料。

$tests[$test_num - 1] =
        { 'ok'       => is the test considered a pass?
          actual_ok  => did it literally say 'ok'?
          name       => name of the test (if any)
          type       => type of test (if any, see below).
          reason     => reason for the above (if any)
        };

如果 Test::Harness 將測試視為通過,則「ok」為 true。

「actual_ok」反映測試是否實際列印「ok」或「not ok」。這是用於檢查「待辦事項」測試的結果。

「name」是測試的名稱。

「type」指出這是否為特殊測試。一般測試的類型為「」。類型可以是下列其中之一

skip        see skip()
todo        see todo()
todo_skip   see todo_skip()
unknown     see below

有時 Test::Builder 測試計數器會在沒有列印任何測試輸出的情況下遞增,例如,當變更 current_test() 時。在這些情況下,Test::Builder 不知道測試的結果,因此其類型為「unknown」。這些測試的詳細資料會填入。它們被視為 ok,但名稱和 actual_ok 會保留為 undef

例如,「not ok 23 - hole count # TODO insufficient donuts」會產生這個結構

$tests[22] =    # 23 - 1, since arrays start from 0.
  { ok        => 1,   # logically, the test passed since its todo
    actual_ok => 0,   # in absolute terms, it failed
    name      => 'hole count',
    type      => 'todo',
    reason    => 'insufficient donuts'
  };
todo
my $todo_reason = $Test->todo;
my $todo_reason = $Test->todo($pack);

如果目前的測試被視為「TODO」,它會回傳原因(如果有)。這個原因可能來自 $TODO 變數或最後一次呼叫 todo_start()

由於 TODO 測試不需要原因,因此這個函式即使在 TODO 區塊內,也可以回傳空字串。使用 $Test->in_todo 來判斷你目前是否在 TODO 區塊內。

todo() 的目的是尋找正確的套件來尋找 $TODO。它在猜測要尋找的正確套件時相當不錯。它會先根據 $Level + 1 尋找呼叫者,因為 todo() 通常在測試函式內呼叫。作為最後手段,它會使用 exported_to()

有時會對於 todo() 應該在哪裡尋找 $TODO 變數感到困惑。如果你想要確定,就明確告訴它要使用哪個 $pack。

find_TODO
my $todo_reason = $Test->find_TODO();
my $todo_reason = $Test->find_TODO($pack);

類似於 todo(),但只會回傳 $TODO 的值,忽略 todo_start()

也可以用於將 $TODO 設定為新值,同時回傳舊值

my $old_reason = $Test->find_TODO($pack, 1, $new_reason);
in_todo
my $in_todo = $Test->in_todo;

如果測試目前在 TODO 區塊內,則回傳 true。

todo_start
$Test->todo_start();
$Test->todo_start($message);

這個方法允許你宣告所有後續測試為 TODO 測試,直到呼叫 todo_end 方法為止。

TODO:$TODO 語法通常很擅長找出我們是否在 TODO 測試中。然而,我們常常發現這無法判斷(例如當我們想要使用 $TODO 但測試在無法事先推論出的其他套件中執行時)。

請注意,你可以使用這個來巢狀「todo」測試

$Test->todo_start('working on this');
# lots of code
$Test->todo_start('working on that');
# more code
$Test->todo_end;
$Test->todo_end;

這通常不建議使用,但大型測試系統常常有奇怪的內部需求。

我們嘗試讓這個也適用於 TODO: 語法,但無法保證,也不建議使用

TODO: {
    local $TODO = 'We have work to do!';
    $Test->todo_start('working on this');
    # lots of code
    $Test->todo_start('working on that');
    # more code
    $Test->todo_end;
    $Test->todo_end;
}

為了安全起見,請選擇一種「TODO」樣式。

todo_end
$Test->todo_end;

停止執行測試作為「TODO」測試。如果在沒有呼叫前置的 todo_start 方法的情況下呼叫此方法,此方法會是致命的。

caller
my $package = $Test->caller;
my($pack, $file, $line) = $Test->caller;
my($pack, $file, $line) = $Test->caller($height);

如同一般的 caller(),但它會根據您的 level() 報告。

$height 會新增到 level()

如果 caller() 結束於堆疊頂端,它會報告最高層級的內容。

結束代碼

如果您的所有測試都通過,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。

執行緒

在 perl 5.8.1 及更新版本中,Test::Builder 是執行緒安全的。測試編號由所有執行緒共用。這表示如果一個執行緒使用 current_test() 設定測試編號,它們都會受到影響。

雖然早於 5.8.1 的版本有執行緒,但它們包含太多錯誤,無法支援。

Test::Builder 只有在 threads.pm 在 Test::Builder 之前 載入時才會執行緒感知。

您可以使用下列其中一項直接停用執行緒支援

$ENV{T2_NO_IPC} = 1

no Test2::IPC;

Test2::API::test2_ipc_disable()

記憶體

一個資訊性的雜湊,可透過 details() 存取,會儲存在您執行的每個測試中。因此記憶體使用量會隨著每個測試執行線性擴充。雖然這對大多數測試套件來說不是問題,但如果您在同一個執行中執行大型(數十萬到數百萬)組合測試,它可能會變成一個問題。

在這種情況下,建議您將測試檔案分割成較小的檔案,或使用反向方法,執行「正常」(程式碼)比較,並在任何意外情況下觸發 fail()

Test::Builder 的未來版本會有方法關閉歷史記錄。

範例

CPAN 可以提供最佳範例。 Test::SimpleTest::MoreTest::ExceptionTest::Differences 全都使用 Test::Builder。

另請參閱

INTERNALS

Test2Test2::API

LEGACY

Test::SimpleTest::More

EXTERNAL

Test::Harness

AUTHORS

原始程式碼由 chromatic 編寫,由 Michael G Schwern <schwern@pobox.com> 維護

MAINTAINERS

Chad Granum <exodist@cpan.org>

COPYRIGHT

著作權所有 2002-2008 chromatic <chromatic@wgz.org> 和 Michael G Schwern <schwern@pobox.com>。

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

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