Test::Tester - 輕鬆測試使用 Test::Builder 建立的測試模組
use Test::Tester tests => 6;
use Test::MyStyle;
check_test(
sub {
is_mystyle_eq("this", "that", "not eq");
},
{
ok => 0, # expect this to fail
name => "not eq",
diag => "Expected: 'this'\nGot: 'that'",
}
);
或
use Test::Tester tests => 6;
use Test::MyStyle;
check_test(
sub {
is_mystyle_qr("this", "that", "not matching");
},
{
ok => 0, # expect this to fail
name => "not matching",
diag => qr/Expected: 'this'\s+Got: 'that'/,
}
);
或
use Test::Tester;
use Test::More tests => 3;
use Test::MyStyle;
my ($premature, @results) = run_tests(
sub {
is_database_alive("dbname");
}
);
# now use Test::More::like to check the diagnostic output
like($results[0]->{diag}, "/^Database ping took \\d+ seconds$"/, "diag");
如果您已根據 Test::Builder 編寫測試模組,Test::Tester 可讓您以最少的精力進行測試。
從版本 0.08 開始,Test::Tester 不再要求您在測試模組中包含任何特殊內容。您只需
use Test::Tester;
在其他任何基於 Test::Builder 的模組之前,在您的測試腳本中使用它,然後就可以開始了。
可以利用其他基於 Test::Builder 的模組來協助測試。事實上,您甚至可以使用模組中的函式來測試同一模組中的其他函式(雖然這可行,但可能不是個好主意,如果您的模組有錯誤,那麼使用它來測試本身可能會得到錯誤的答案)。
測試最簡單的方法是執行類似以下的動作
check_test(
sub { is_mystyle_eq("this", "that", "not eq") },
{
ok => 0, # we expect the test to fail
name => "not eq",
diag => "Expected: 'this'\nGot: 'that'",
}
);
這將執行 is_mystyle_eq 測試,擷取其結果並檢查它們是否符合預期。
您可能需要以更靈活的方式檢查測試結果,例如,診斷輸出可能很長或很複雜,或者它可能涉及您無法預先預測的事情,例如時間戳記。在這種情況下,您可以直接存取測試結果
my ($premature, @results) = run_tests(
sub {
is_database_alive("dbname");
}
);
like($result[0]->{diag}, "/^Database ping took \\d+ seconds$"/, "diag");
或
check_test(
sub { is_mystyle_qr("this", "that", "not matching") },
{
ok => 0, # we expect the test to fail
name => "not matching",
diag => qr/Expected: 'this'\s+Got: 'that'/,
}
);
我們無法預測資料庫 ping 會花費多長時間,因此我們使用 Test::More 的 like() 測試來檢查診斷字串是否為正確的形式。
這只適用於向後相容性
讓您的模組使用 Test::Tester::Capture 物件,而不是 Test::Builder 物件。如何執行此操作取決於您的模組,但假設您的模組將 Test::Builder 物件保存在 $Test 中,並且您的所有測試常式透過 $Test 存取它,然後提供類似以下的函式
sub set_builder
{
$Test = shift;
}
應該允許您的測試腳本執行
Test::YourModule::set_builder(Test::Tester->capture);
在那之後,模組中的任何測試都將被擷取。
每個測試的結果都擷取在雜湊中。這些雜湊與 Test::Builder->details 傳回的雜湊相同,但多了幾個額外的欄位。
這些欄位記載在 Test::Builder 的 details() 函式中
測試是否通過?
測試是否真的通過?也就是說,通過是來自 Test::Builder->ok(),還是因為它是 TODO 測試而通過?
提供給測試的名稱。
測試的類型?可能性包括跳過、待辦事項等。請參閱 Test::Builder 以取得更多詳細資料。
跳過、待辦事項等的原因。請參閱 Test::Builder 以取得更多詳細資料。
這些欄位專屬於 Test::Tester。
為測試輸出的任何診斷。這僅包含在宣告測試結果之後輸出的診斷。
請注意,Test::Builder 會確保所有診斷以 \n 結尾,而在 Test::Tester 的早期版本中,預期的診斷中最後一個 \n 是必要的。從版本 0.10 開始,如果您忘記了,Test::Tester 會新增 \n。如果您不預期任何診斷,它不會新增 \n。請參閱下方,以取得追蹤難以找到的空白和標籤相關問題的協助。
這讓您可以檢查測試模組是否設定了 $Test::Builder::Level 的正確值,並在測試失敗時提供正確的檔案和行號。它是透過檢視 caller() 和 $Test::Builder::Level 計算的。它應該計算在跳進您要測試的函式之前有多少個子常式。例如,在
run_tests( sub { my_test_function("a", "b") } );
深度應該是 1,而在
sub deeper { my_test_function("a", "b") }
run_tests(sub { deeper() });
深度應該是 2,也就是 sub {} 的 1 和 deeper() 的 1。這看起來可能有點複雜,但如果您的測試看起來像此文件中的簡單範例,您就不必擔心,因為深度將永遠是 1,而這是 Test::Tester 預設的預期值。
注意:如果您沒有在 check_test() 中指定 depth 的值,它會自動將其與 1 比較,如果您真的想要略過深度測試,請傳入 undef。
注意:深度將無法正確計算從訊號處理常式、END 區塊或隱藏呼叫堆疊的任何其他地方執行的測試。
Test::Tester 的某些函式會傳回這些雜湊的陣列,就像 Test::Builder->details 一樣。也就是說,第一個測試的雜湊將是陣列元素 1(不是 0)。元素 0 不是雜湊,它將是包含在第一個測試之前出現的任何診斷輸出的字串。這通常應該是空的,如果不是,表示在任何測試結果顯示之前,某些東西輸出了診斷。
外觀可能會產生誤導,尤其是在空值時。如果您抓著頭試圖找出 Test::Tester 為什麼說您的診斷錯誤,而它們看起來完全正確,那麼答案可能是空白。從版本 0.10 開始,Test::Tester 會用單引號包圍預期的和取得的診斷值,以方便找出尾隨空白。因此,在此範例中
# Got diag (5 bytes):
# 'abcd '
# Expected diag (4 bytes):
# 'abcd'
很明顯第一個字串的結尾有一個空白。解決此問題的另一種方法是在 ANSI 終端機上使用顏色和反向視訊,如果您想要這樣做,請參閱下方的顏色。
不幸的是,有時候這還不夠,顏色和引號都無法幫助您解決涉及標籤、其他非列印字元和 Unicode 中固有的某些種類問題的問題。為了解決此問題,您可以將 Test::Tester 切換到一種模式,其中所有「棘手的」字元都顯示為 \{xx}。棘手的字元是指 ASCII 碼小於 33 或大於 126 的字元。這使得輸出更難閱讀,但更容易找出字串之間的細微差異。若要開啟此模式,請在您的測試指令碼中呼叫 show_space()
或將 TESTTESTERSPACE
環境變數設定為 true 值。上述範例將看起來像
# Got diag (5 bytes):
# abcd\x{20}
# Expected diag (4 bytes):
# abcd
如果您偏好使用顏色作為尋找棘手的空白字元的工具,您可以將 TESTTESTCOLOUR
環境變數設定為一對以逗號分隔的顏色,第一個是前景顏色,第二個是背景顏色。例如,「white,red」會在紅色背景上列印白色文字。這需要 Term::ANSIColor 模組。您可以指定任何 Term::ANSIColor::color 函式可以接受的顏色。
如果您拼寫顏色不同,那沒問題。TESTTESTERCOLOR
變數也行(如果兩個都設定,則英國拼法獲勝)。
\&test_sub 是對子例程的參考。
run_tests 執行 $test_sub 中的子例程,並擷取其內部任何測試的結果。如果您願意,可以在這個子例程中執行超過 1 個測試。
$premature 是包含第一個測試之前所有診斷輸出的字串。
@results 是測試結果雜湊的陣列。
\%result 是對測試結果雜湊的參考。
\%expect 是對測試結果預期值的雜湊的參考。
cmp_result 將結果與預期值進行比較。如果發現任何差異,它會輸出診斷。您可以從預期結果中省略任何欄位,而 cmp_result 將不會對該欄位進行比較。
\@results 是對測試結果陣列的參考。
\@expects 是對雜湊參考陣列的參考。
cmp_results 檢查結果是否與預期結果相符,如果發現任何差異,它會輸出診斷。它首先檢查 \@results 和 \@expects 中的元素數量是否相同。然後,它逐一檢查每個結果,並根據上述 cmp_result() 將其與預期結果進行比較。
\&test_sub 是對子例程的參考。
\@expect 是對預期測試結果的雜湊參考陣列的參考。
check_tests 將 run_tests 和 cmp_tests 結合到單一呼叫中。它也會檢查測試是否在任何階段中斷。
它傳回與 run_tests 相同的值,因此您可以在需要時進一步檢查測試結果。
\&test_sub 是對子例程的參考。
\%expect 是對測試結果預期值的雜湊的參考。
check_test 是 check_tests 的包裝器。它將 run_tests 和 cmp_tests 結合到單一呼叫中,檢查測試是否中斷。它假設在 \&test_sub 內部只執行一個測試,並包含一個測試以確保為真。
它傳回與 run_tests 相同的值,因此您可以在需要時進一步檢查測試結果。
開啟字元跳脫,如 SPACES AND TABS 區段所述。
通常,測試模組(我們稱之為 Test:MyStyle)會呼叫 Test::Builder->new 來取得 Test::Builder 物件。Test::MyStyle 會呼叫此物件上的方法來記錄測試結果的資訊。當載入 Test::Tester 時,它會將 Test::Builder 的 new() 方法替換為會傳回 Test::Tester::Delegate 物件的方法。大部分時間,此物件會像真正的 Test::Builder 物件一樣運作。任何被呼叫的方法都會委派給真正的 Test::Builder 物件,因此一切運作正常。然而,一旦我們進入測試模式,方法呼叫就不會再傳遞給真正的 Test::Builder 物件,而是傳遞給 Test::Tester::Capture 物件。此物件看起來就像真正的 Test::Builder 物件,只不過它不會輸出測試結果和診斷,而只是記錄所有資訊以供後續分析。
呼叫 Test::Builder->note 的支援很有限。它實作為一個空的 stub,因此使用它的模組不會崩潰,但呼叫不會像其他呼叫一樣記錄下來以供測試。歡迎提供修正程式。
Test::Builder 測試的優良來源。 Test::Builder::Tester 是 Test::Tester 所解決問題的另一種方法 - 擷取 Test::Builder 輸出的字串。這表示您無法個別存取個別資訊,而且您必須完全預測您的測試會輸出什麼。
此模組的著作權為 2005 年 Fergal Daly <fergal@esatclear.ie> 所有,某些部分根據其他人的著作改編。
計畫處理從 Test::More 擷取。由 Michael G Schwern <schwern@pobox.com> 所撰寫。
Test::Tester::Capture 是精簡且經過修改的 Test::Builder 版本。Test::Builder 由 chromatic <chromatic@wgz.org> 和 Michael G Schwern <schwern@pobox.com> 所撰寫。
與 Perl 本身採用相同的授權
請參閱 http://www.perl.com/perl/misc/Artistic.html