Test2::API - 撰寫 Test2 基礎測試工具的主要介面。
此套件的內部結構隨時可能變更!提供的公開方法不會以向下不相容的方式變更 (一旦有穩定版本),但底層實作細節可能會變更。請勿在此處破壞封裝!
目前實作是建立 Test2::API::Instance 物件的單一執行個體。所有類別方法都遞延到單一執行個體。沒有公開存取單例,這是故意的。此套件提供的類別方法提供唯一公開的公開功能。
執行此項操作主要是為了避免 Test::Builder 公開其單例時遇到的問題。我們不希望任何人取代此單例、重新祝福它,或直接破壞其內部結構。如果您需要執行某些操作,但由於此處的限制而無法執行,請將其報告為問題。如果可能,我們將建立一種方法,讓您在不公開不應公開的事項的情況下實作您的功能。
此套件匯出所有用於撰寫和/或驗證測試工具所需的功能。使用這些建構模組,您可以開始非常快速地撰寫測試工具。您還可以使用這些工具來測試您撰寫的工具。
context()
方法是您進入 Test2 架構的主要介面。
package My::Ok;
use Test2::API qw/context/;
our @EXPORT = qw/my_ok/;
use base 'Exporter';
# Just like ok() from Test::More
sub my_ok($;$) {
my ($bool, $name) = @_;
my $ctx = context(); # Get a context
$ctx->ok($bool, $name);
$ctx->release; # Release the context
return $bool;
}
請參閱 Test2::API::Context 以取得 context 物件上可用的方法清單。
intercept { ... }
工具讓您暫時攔截測試系統產生的所有事件
use Test2::API qw/intercept/;
use My::Ok qw/my_ok/;
my $events = intercept {
# These events are not displayed
my_ok(1, "pass");
my_ok(0, "fail");
};
從版本 1.302178 開始,這現在會傳回一個 arrayref,它也是 Test2::API::InterceptResult 的一個執行個體。請參閱 Test2::API::InterceptResult 文件,以取得如何最佳使用它的詳細資訊。
use Test2::API qw{
test2_init_done
test2_stack
test2_set_is_end
test2_get_is_end
test2_ipc
test2_formatter_set
test2_formatter
test2_is_testing_done
};
my $init = test2_init_done();
my $stack = test2_stack();
my $ipc = test2_ipc();
test2_formatter_set($FORMATTER)
my $formatter = test2_formatter();
... And others ...
所有匯出都是選用的。您必須指定要匯入的子程式。
use Test2::API qw/context intercept run_subtest/;
這是最常需要的匯出清單。如果您只是在撰寫工具,那麼這可能是您唯一需要的。如果您需要一些東西,卻在此處找不到,那麼您也可以查看 "其他 API 匯出"。
這些匯出由於其重要性/普遍性而沒有 'test2_' 前綴。"其他 API 匯出" 區段中的匯出具有 'test2_' 前綴,以確保它們顯著突出。
用法
context()
函式將永遠傳回目前的 context。如果已經有一個 context 處於作用中,它將會被傳回。如果沒有作用中的 context,將會產生一個。當產生一個 context 時,它將預設使用目前執行的子程式被呼叫的檔案和行號。
請參閱 "Test2::API::Context 中的 CRITICAL DETAILS",以取得關於取得 context 後您可以和不可以執行的重要規則。
注意如果您忽略它回傳的內容物件,這個函式會擲回例外。
注意在 perl 5.14+ 中,深度檢查用於確保沒有內容外洩。由於 https://rt.perl.org/Public/Bug/Display.html?id=127774,在較舊的 perl 中無法安全地執行此操作。您可以在載入 Test2::API 之前透過設定 $ENV{T2_CHECK_DEPTH} = 1
或 $Test2::API::DO_DEPTH_CHECK = 1
強制啟用它。
context
的所有參數都是選用的。
如果您必須在比進入點更深的子程式中取得內容,您可以使用這個參數告訴它回溯多少額外的堆疊框架。如果未提供此選項,則使用預設值 0
。
sub third_party_tool {
my $sub = shift;
... # Does not obtain a context
$sub->();
...
}
third_party_tool(sub {
my $ctx = context(level => 1);
...
$ctx->release;
});
如果您需要撰寫自己的工具來包裝對 context()
的呼叫,並打算讓它回傳內容物件,請使用這個參數。
sub my_context {
my %params = ( wrapped => 0, @_ );
$params{wrapped}++;
my $ctx = context(%params);
...
return $ctx;
}
sub my_tool {
my $ctx = my_context();
...
$ctx->release;
}
如果您沒有這樣做,那麼您呼叫的工具也會檢查內容,它們會注意到它們取得的內容是在相同的堆疊深度建立的,這會觸發保護措施,警告您並摧毀現有的內容。
通常,context()
會查看全域 hub 堆疊。如果您正在維護自己的 Test2::API::Stack 執行個體,您可以傳遞它以用來取代全域執行個體。
如果您想要取得特定 hub 的內容,而不是堆疊頂端的任何內容,請使用這個參數。
這讓您可以提供一個回呼子程式,只有在您的 context()
呼叫產生新的內容時,才會呼叫它。如果 context()
回傳現有的內容,則不會呼叫回呼。傳遞給回呼的唯一引數將是內容物件本身。
sub foo {
my $ctx = context(on_init => sub { 'will run' });
my $inner = sub {
# This callback is not run since we are getting the existing
# context from our parent sub.
my $ctx = context(on_init => sub { 'will NOT run' });
$ctx->release;
}
$inner->();
$ctx->release;
}
這可讓您提供一個回呼子,在釋放內容實例時會呼叫它。即使傳回現有的內容,也會將此回呼子新增至傳回的內容。如果呼叫內容多次新增回呼子,則在最後釋放內容時,所有回呼子都會按反向順序呼叫。
sub foo {
my $ctx = context(on_release => sub { 'will run second' });
my $inner = sub {
my $ctx = context(on_release => sub { 'will run first' });
# Neither callback runs on this release
$ctx->release;
}
$inner->();
# Both callbacks run here.
$ctx->release;
}
用法
這是一個捷徑,可讓您在一個陳述式中釋放內容並傳回一個值。此函式會取得您的內容,以及一個選用的傳回值。它會釋放您的內容,然後傳回您的值。它總是假設是純量內容。
sub tool {
my $ctx = context();
...
return release $ctx, 1;
}
當您想要傳回從呼叫需要查看目前內容的函式所取得的值時,此工具最為有用
my $ctx = context();
my $out = some_tool(...);
$ctx->release;
return $out;
我們可以將上述最後 3 行合併如下
my $ctx = context();
release $ctx, some_tool(...);
用法
sub my_tool {
context_do {
my $ctx = shift;
my (@args) = @_;
$ctx->ok(1, "pass");
...
# No need to call $ctx->release, done for you on scope exit.
} @_;
}
在您的測試工具中使用此工具可為您處理許多樣板。它會確保取得內容。它會擷取並重新擲回任何例外。它會確保在您完成時釋放內容。它會保留子常式呼叫內容(陣列、純量、空值)。
這是撰寫測試工具最安全的方法。此方法僅有兩個缺點:效能略微下降,以及來源程式碼中會有一些額外的縮排。如果您覺得縮排有問題,可以看看下一部分。
用法
sub my_tool(&) {
my $code = shift;
my $ctx = context();
...
no_context {
# Things in here will not see our current context, they get a new
# one.
$code->();
};
...
$ctx->release;
};
此工具會隱藏一段程式碼區塊的內容。這表示在區塊中執行的任何工具如果取得內容,就會取得一個全新的內容。新的內容會由取得它的工具下方巢狀的工具繼承。
這通常會隱藏頂級集線器的目前內容。如果您需要隱藏其他集線器的內容,您可以傳入選用的 $hid
參數。
用法
my $events = intercept {
ok(1, "pass");
ok(0, "fail");
...
};
此函式將程式區塊作為其唯一引數,並具有原型。它將執行程式區塊,攔截過程中產生的任何事件。它將傳回一個包含所有已產生事件物件的陣列參考。所有事件都應該是 Test2::Event 的子類別。
從 1.302178 版開始,傳回的事件陣列會以 Test2::API::InterceptResult 執行個體的形式進行 blssed。 Test2::API::InterceptResult 提供一個有用的介面,用於過濾和/或檢查事件清單整體,或清單中的個別事件。
這旨在幫助您測試您的測試程式碼。這不適用於僅撰寫測試的人員。
用法
run_subtest($NAME, \&CODE, $BUFFERED, @ARGS)
# or
run_subtest($NAME, \&CODE, \%PARAMS, @ARGS)
這將使用 @args
中的引數執行提供的程式區塊。此程式區塊將作為子測試執行。子測試是一個孤立的測試狀態,它濃縮成單一的 Test2::Event::Subtest 事件,其中包含在子測試中產生的所有事件。
子測試的名稱。
在子測試中執行的程式碼。
如果這是一個簡單的純量,則它將被視為 'buffered' 設定的布林值。如果這是一個雜湊參考,則它將被用作參數雜湊。參數雜湊將用於 hub 建構(移除指定的鍵)。
由 run_subtest 移除並使用的鍵
您希望傳遞到子測試程式碼中的任何額外參數。
通常,子測試內部和外部的所有事件都會由 hub 立即傳送給格式化程式。有時,最好等到子測試完成後才傳送事件。這通常取決於所使用的格式化程式。
在兩種情況下,事件都會產生並儲存在陣列中。此陣列最終用於在子測試結束時產生的 Test2::Event::Subtest 事件中填入 subevents
屬性。此標記不會影響此部分,它總是會發生。
在子測試結束時,最終的 Test2::Event::Subtest 事件會傳送給格式化程式。
Test2::Event::Subtest 事件的 buffered
屬性會設定為此標記的值。這表示任何查看事件的格式化程式、監聽器等都會知道它是否已緩衝。
緩衝子測試中的事件可能會或可能不會在發生時傳送給格式化程式。如果格式化程式無法指定,則預設為不傳送事件,因為它們已產生,而格式化程式可以從 subevents
屬性中提取它們。
格式化程式可以透過實作 hide_buffered()
方法來指定。如果此方法傳回 true,則在緩衝子測試中產生的事件將不會獨立於最終子測試事件傳送。
這個用法的一個範例是 Test2::Formatter::TAP 格式化器。對於未緩衝的子測試,事件會在產生時呈現。在子測試結束時,會呈現最後的子測試事件,但會忽略 subevents
屬性。對於緩衝的子測試,會發生相反的情況,事件不會在產生時呈現,而是使用 subevents
屬性一次呈現所有事件。這在並行執行子測試時很有用,因為沒有這個屬性,子測試的輸出會交錯在一起。
本節中的輸出通常不需要。這些輸出都加上 'test2_' 前綴,以確保它們脫穎而出。您應該先查看 "主要 API 輸出" 部分,再查看這裡。本部分是「能力越大,責任越大」的範例。如果您不謹慎使用這些輸出,可能會造成嚴重問題。
所有輸出都是選擇性的。您需要在匯入時列出您要使用的輸出
use Test2::API qw/test2_init_done .../;
這些輸出提供對內部狀態和物件實例的存取權。
如果堆疊和 IPC 實例已經初始化,這個輸出會傳回 true。如果它們尚未初始化,這個輸出會傳回 false。初始化會在最晚的時候發生。它會在工具請求 IPC 實例、格式化器或堆疊時發生。
這個輸出會傳回 loaded 旗標的布林值。如果 Test2 已完成載入,這個輸出會傳回 true,否則會傳回 false。載入會在工具第一次請求內容時完成。
這個輸出用於切換 Test2 認為 END 階段已經開始的信念。如果沒有參數,這個輸出會將其設定為 true。如果有參數,這個輸出會將其設定為第一個參數的值。
這用於防止在 END 區塊中使用 caller()
,這可能會導致段落錯誤。這僅在可能有多個 END 階段的一些持續環境中需要。
檢查 Test2 是否認為這是 END 階段。
這將傳回全域 Test2::API::Stack 執行個體。如果尚未初始化,現在將初始化。
如果測試已完成且不應傳送其他事件,這將傳回 true。這在警告處理常式等項目中很有用,在這些項目中您可能想要將警告轉換為事件,但在測試完成時需要它們開始像正常警告一樣作用。
$SIG{__WARN__} = sub {
my ($warning) = @_;
if (test2_is_testing_done()) {
warn @_;
}
else {
my $ctx = context();
...
$ctx->release
}
}
停用 IPC。
檢查 IPC 是否已停用。
這些可用於開啟和關閉 IPC 等待,或檢查標記的目前值。
等待預設為開啟。等待將導致父處理程序/執行緒在退出前等待所有子處理程序和執行緒完成。您幾乎永遠都不會想要關閉這個功能。
不建議:這是一個令人困惑的介面,最好使用 test2_ipc_wait_enable()
、test2_ipc_wait_disable()
和 test2_ipc_wait_enabled()
。
這可用於取得/設定 no_wait 狀態。等待預設為開啟。等待將導致父處理程序/執行緒在退出前等待所有子處理程序和執行緒完成。您幾乎永遠都不會想要關閉這個功能。
這些函式傳回應寫入測試輸出的檔案控制代碼。它們主要在撰寫自訂格式化器和將事件轉換為實際輸出的程式碼(TAP 等)時很有用。它們將傳回格式化輸出可以傳送到的原始檔案控制代碼的重複,無論目前執行的測試可能將 STDOUT 和 STDERR 留在什麼狀態。
重新複製 test2_stdout()
和 test2_stderr()
從目前的 STDOUT 和 STDERR 回傳的內部檔案處理常式。除了在非常特殊的情況下,你不需要這麼做(例如,你正在測試一個新的格式化器,你需要控制格式化器將輸出傳送至何處。)
這些掛鉤允許你將自訂行為加入 Test2 和建立在其上的工具所執行的動作。
這可用於加入一個在所有測試完成後呼叫的回呼。這對於加入額外結果來說太遲了,此回呼的主要用途是設定結束代碼。
test2_add_callback_exit(
sub {
my ($context, $exit, \$new_exit) = @_;
...
}
);
傳入的 $context
將會是 Test2::API::Context 的一個實例。$exit
參數將會是任何東西修改它之前的原始結束代碼。$$new_exit
是新結束代碼的參考。你可以修改它來變更結束代碼。請注意,$$new_exit
可能已經與 $exit
不同
加入一個在 Test2 完成載入時將會呼叫的回呼。這表示回呼將會執行一次,在第一次取得內容時。如果 Test2 已經完成載入,則回呼將會立即執行。
這將你的代碼參考加入到 Test2 完成載入後的根集線器後續動作中。
這基本上是一個執行下列動作的幫手
test2_add_callback_post_load(sub {
my $stack = test2_stack();
$stack->top; # Insure we have a hub
my ($hub) = Test2::API::test2_stack->all;
$hub->set_active(1);
$hub->follow_up(sub { ... }); # <-- Your coderef here
});
新增一個回呼函式,每次有人嘗試取得內容時就會呼叫它。這會在每次呼叫 context()
時呼叫。它會取得一個單一參數,即用於建構內容的參數雜湊的參考。這時您可以直接變更雜湊來變更參數。
test2_add_callback_context_acquire(sub {
my $params = shift;
$params->{level}++;
});
這是一個非常可怕的 API 函式。除非您有需要,否則請勿使用。這是在 Test::Builder 和向後相容性中使用的。由於效能因素,這會讓您直接操作雜湊,而不是傳回新的雜湊。
新增一個回呼函式,每次建立新的內容時就會呼叫它。回呼函式會將新建立的內容作為其唯一參數接收。
新增一個回呼函式,每次釋放內容時就會呼叫它。回呼函式會將釋放的內容作為其唯一參數接收。
新增一個回呼函式,每次要執行子測試時就會呼叫它。回呼函式會接收子測試名稱、代碼參考和任何參數。
傳回所有內容取得回呼函式參考。
傳回所有內容初始化回呼函式參考。
傳回所有內容釋放回呼函式參考。
傳回所有離開回呼函式參考。
傳回所有載入後回呼函式參考。
傳回所有子測試前回呼函式參考。
這讓您可以提供 UUID 產生器。如果提供,UUID 會附加到所有事件、樞紐和內容。這對於儲存、追蹤和連結這些物件很有用。
您提供的子程式應始終傳回一個唯一的識別碼。大多數情況下會需要一個適當的 UUID 字串,但 Test2::API 中並未強制執行這項規定。
子程式將收到一個參數,即標記為「context」、「hub」或「event」的物件類型。未來可能會標記其他物件,屆時將傳入新的字串。這些純粹是提供資訊,您可以(且通常應該)忽略它們。
這些讓您可以存取或指定 IPC 系統內部元件。
檢查 IPC 是否已啟用。
這將傳回全域 Test2::IPC::Driver 執行個體。如果尚未初始化,則現在會進行初始化。
將 IPC 驅動程式新增至清單。這會將驅動程式新增至清單的開頭。
取得 IPC 驅動程式的清單。
檢查是否已啟用輪詢。
開啟輪詢。每次建立 context 時,這會從其他程序和執行緒中刪除事件。
關閉 IPC 輪詢。
舊版,目前這是一個無操作的 no-op,會傳回 0;
告訴其他程序和事件有一個事件正在處理中。$uniq_val
應為唯一值,不會由其他執行緒/程序產生。
注意:呼叫此函式後,test2_ipc_get_pending()
會傳回 1。這是故意的,無法避免。
如果沒有辦法檢查(假設為是),則傳回 -1
如果(很可能)沒有待處理事件,這會傳回 0。
如果(很可能)有待處理事件,這會傳回 1。傳回後它會重設,沒有其他東西能看到有待處理事件。
取得/設定 IPC 系統的逾時值。這個逾時值是 IPC 系統在中止子行程和執行緒之前,會等待它們完成的時間長度。
預設值是 30
秒。
這些讓您可以存取或指定可以/應該使用的格式器。
這會傳回全域格式器類別。這不是一個執行個體。預設情況下,格式器設定為 Test2::Formatter::TAP。
您可以使用 T2_FORMATTER
環境變數覆寫這個預設值。
通常會在環境變數中的值前面加上 'Test2::Formatter::'
$ T2_FORMATTER='TAP' perl test.t # Use the Test2::Formatter::TAP formatter
$ T2_FORMATTER='Foo' perl test.t # Use the Test2::Formatter::Foo formatter
如果您想要指定一個完整的模組名稱,請使用 '+' 前綴
$ T2_FORMATTER='+Foo::Bar' perl test.t # Use the Foo::Bar formatter
設定全域格式器類別。這只能設定一次。注意:這會覆寫 'T2_FORMATTER' 環境變數中指定的所有內容。
取得所有已載入格式器的清單。
將一個格式器加入清單。最後加入的格式器會在初始化時使用。如果在初始化後呼叫這個,會發出一個警告。
請參閱此發行版中包含的 /Examples/
目錄。
Test2::API::Context - 內容物件的詳細文件。
Test2::IPC - 用於執行緒/分岔支援的 IPC 系統。
Test2::Formatter - 格式器,例如 TAP,存在於此處。
Test2::Event - 事件存在於這個命名空間中。
Test2::Hub - 所有事件最終會透過一個集線器傳遞。自訂集線器是 intercept()
和 run_subtest()
的實作方式。
這個套件有一個 END 函式區塊。這個 END 函式區塊負責根據測試結果設定結束代碼。這個結束函式區塊也會呼叫可以新增到這個套件的回呼函式。
Test2 的原始碼儲存庫可以在 http://github.com/Test-More/test-more/ 找到。
版權所有 2020 Chad Granum <exodist@cpan.org>。
這個程式是自由軟體;您可以在與 Perl 相同的條款下重新散布或修改它。
請參閱 http://dev.perl.org/licenses/