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::Simple 和 Test::More 已證明是熱門的測試模組,但它們並不總是足夠靈活。Test::Builder 提供一個建構區塊,您可以在其上撰寫自己的測試函式庫,這些函式庫可以一起使用。
my $Test = Test::Builder->new;
傳回表示測試目前狀態的 Test::Builder 物件。
由於您只執行每個程式一個測試,因此 new
始終傳回相同的 Test::Builder 物件。不論您呼叫 new()
多少次,您都將取得相同的物件。這稱為單例。這樣做是為了讓多個模組共用全域資訊,例如測試計數器和測試輸出位置。
如果您想要一個與單例不同的全新 Test::Builder 物件,請使用 create
。
my $Test = Test::Builder->create;
好的,因此可以有多個 Test::Builder 物件,而這就是取得它的方式。如果您要測試基於 Test::Builder 的模組,您可以使用這個方法取代 new()
,但否則您可能需要 new
。
注意:實作尚未完成。例如,level
仍由所有 Test::Builder 物件共用,即使是使用此方法建立的物件也是如此。此外,方法名稱可能會在未來變更。
$builder->subtest($name, \&subtests, @args);
請參閱 Test::More 中 subtest
的文件。
subtest
也會接受引數(這是選用的),這些引數會傳遞給子測試參考。
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
找出是否已定義計畫。$plan
為 undef
(未設定計畫)、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
永遠是選用的。
$Test->ok($test, $name);
您的基本測試。如果 $test
為 true,則通過,如果 $test 為 false,則失敗。就像 Test::Simple 的 ok()
。
$Test->is_eq($got, $expected, $name);
就像 Test::More 的 is()
。檢查 $got eq $expected
。這是字串版本。
undef
僅與另一個 undef
相符。
$Test->is_num($got, $expected, $name);
就像 Test::More 的 is()
。檢查 $got == $expected
。這是數字版本。
undef
僅與另一個 undef
相符。
$Test->isnt_eq($got, $dont_expect, $name);
就像 Test::More 的 isnt()
。檢查 $got ne $dont_expect
。這是字串版本。
$Test->isnt_num($got, $dont_expect, $name);
就像 Test::More 的 isnt()
。檢查 $got ne $dont_expect
。這是數字版本。
$Test->like($thing, qr/$regex/, $name);
$Test->like($thing, '/$regex/', $name);
就像 Test::More 的 like()
。檢查 $thing 是否與給定的 $regex
相符。
$Test->unlike($thing, qr/$regex/, $name);
$Test->unlike($thing, '/$regex/', $name);
就像 Test::More 的 unlike()
。檢查 $thing 不與給定的 $regex
相符。
$Test->cmp_ok($thing, $type, $that, $name);
就像 Test::More 的 cmp_ok()
一樣。
$Test->cmp_ok($big_num, '!=', $other_big_num);
這些方法用於撰寫測試,但本身並非測試。
$Test->BAIL_OUT($reason);
向 Test::Harness 指出情況非常糟糕,所有測試都應終止。這包括執行任何其他測試腳本。
它將以 255 退出。
$Test->skip;
$Test->skip($why);
略過目前的測試,報告 $why
。
$Test->todo_skip;
$Test->todo_skip($why);
就像 skip()
,只不過它會宣告測試失敗且為待辦事項。類似於
print "not ok $tnum # TODO $why\n";
撰寫自己的測試方法時,這些方法很有用。
$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);
}
my $is_fh = $Test->is_fh($thing);
判斷指定的 $thing
是否可用作檔案控制代碼。
$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
,而不是將它設定為常數。
$Test->use_numbers($on_or_off);
測試是否應該輸出數字。也就是說,如果為真
ok 1
ok 2
ok 3
或如果為假
ok
ok
ok
當您無法依賴測試輸出順序時,這最有用,例如涉及執行緒或分岔時。
預設為開啟。
$Test->no_diag($no_diag);
如果設定為真,則不會印出任何診斷。這包括對 diag()
的呼叫。
$Test->no_ending($no_ending);
通常,Test::Builder 在測試結束時會執行一些額外的診斷。它也會變更退出代碼,如下所述。
如果這是真的,則不會執行任何這些操作。
$Test->no_header($no_header);
如果設定為 true,則不會列印「1..N」標頭。
控制測試輸出位置。
您的測試可以變更 STDOUT 和 STDERR 指向的位置,Test::Builder 的預設輸出設定不會受到影響。
$Test->diag(@msgs);
列印指定的 @msgs
。與 print
一樣,參數會直接附加在一起。
通常,它會使用 failure_output()
處理常式,但如果這是 TODO 測試,則會使用 todo_output()
處理常式。
輸出會縮排並標記為 #,以避免干擾測試輸出。如果最後沒有換行,則會在最後加上換行。
我們建議使用這個,而不是直接呼叫 print。
傳回 false。為什麼?因為 diag()
通常與失敗的測試一起使用 (ok() || diag()
),它會「傳遞」失敗。
return ok(...) || diag(...);
$Test->note(@msgs);
與 diag()
類似,但它會列印至 output()
處理常式,因此使用者通常不會看到它,除非是在詳細模式下。
my @dump = $Test->explain(@msgs);
會以人類可讀的格式傾印任何參考的內容。對於像...之類的東西來說很方便
is_deeply($have, $want) || diag explain $have;
或
is_deeply($have, $want) || note explain $have;
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。
$tb->reset_outputs;
將所有輸出檔案控制碼重設回其預設值。
$tb->carp(@message);
使用 @message
警告,但訊息會顯示為來自原始測試函式被呼叫的點 ($tb->caller
)。
$tb->croak(@message);
使用 @message
死亡,但訊息會顯示為來自原始測試函式被呼叫的點 ($tb->caller
)。
這將關閉結果長期儲存。呼叫此方法會使 details
和 summary
無用。如果你執行的測試足夠多,以填滿所有可用記憶體,你可能想使用這個方法。
Test::Builder->new->no_log_results();
沒有辦法重新開啟它。
my $curr_test = $Test->current_test;
$Test->current_test($num);
取得/設定我們目前進行的測試編號。您通常不必設定這個。
如果設定為前進,遺失測試的詳細資料會填入為「未知」。如果設定為後退,介入測試的詳細資料會刪除。如果您真的想要的話,可以清除歷史記錄。
my $ok = $builder->is_passing;
指出測試套件目前是否通過。
更正式地說,如果發生任何讓測試套件無法通過的事情,它將為 false。否則為 true。
例如,如果沒有執行任何測試,is_passing()
將為 true,因為即使沒有測試的套件會失敗,您也可以新增通過的測試並開始通過。
不要想太多。
my @tests = $Test->summary;
到目前為止的測試的簡單摘要。通過為 true,失敗為 false。這是一個邏輯上的通過/失敗,因此待辦事項是通過。
當然,測試 #1 是 $tests[0],等等...
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'
};
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。
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);
my $in_todo = $Test->in_todo;
如果測試目前在 TODO 區塊內,則回傳 true。
$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
方法的情況下呼叫此方法,此方法會是致命的。
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::Simple、Test::More、Test::Exception 和 Test::Differences 全都使用 Test::Builder。
原始程式碼由 chromatic 編寫,由 Michael G Schwern <schwern@pobox.com> 維護
著作權所有 2002-2008 chromatic <chromatic@wgz.org> 和 Michael G Schwern <schwern@pobox.com>。
此程式為自由軟體;您可以在與 Perl 相同的條款下重新散布或修改它。
請參閱 http://www.perl.com/perl/misc/Artistic.html