Test2::API::Context - 表示測試情境的物件。
情境物件是使用 Test2 編寫的測試工具作者的主要介面。情境物件表示測試發生的情境(檔案和行號),並提供從該情境產生事件的快速方法。情境物件也會負責將事件傳送給正確的 Test2::Hub 執行個體。
一般來說,您不會直接建立情境。若要取得情境,您應該始終使用 Test2::API 模組匯出的 context()
。
use Test2::API qw/context/;
sub my_ok {
my ($bool, $name) = @_;
my $ctx = context();
if ($bool) {
$ctx->pass($name);
}
else {
$ctx->fail($name);
}
$ctx->release; # You MUST do this!
return $bool;
}
情境物件可以輕鬆包裝也使用情境的其它工具。一旦您取得情境,在釋放情境之前您呼叫的任何工具都會繼承它
sub wrapper {
my ($bool, $name) = @_;
my $ctx = context();
$ctx->diag("wrapping my_ok");
my $out = my_ok($bool, $name);
$ctx->release; # You MUST do this!
return $out;
}
透過 Test2::API::Context->new()
建立您自己的情境幾乎不會產生理想的結果。使用 Test2::API 匯出的 context()
。
在少數情況下,工具作者可能想要手動建立新的內容,這就是 new
方法存在的理由。除非你真的知道自己在做什麼,否則你應該避免這麼做。
釋放內容會告訴系統你已經使用完它。這會讓系統有機會執行任何必要的回呼或清理工作。如果你忘記釋放內容,它會嘗試偵測問題並警告你。
當你取得內容物件時,它是專門為你的工具和任何巢狀工具建立的。如果你傳遞內容,你就有可能讓其他工具受到不正確的內容資訊污染。
如果你確定要讓不同的工具使用相同的內容,你可以傳遞快照。$ctx->snapshot
會提供內容的淺層複製,可以安全地傳遞或儲存。
只要內容存在於特定樞紐,所有嘗試取得內容的工具都會取得現有執行個體。如果你嘗試儲存內容,你會讓其他工具受到不正確的內容資訊污染。
如果你確定要儲存內容以供稍後使用,你可以使用快照。$ctx->snapshot
會提供內容的淺層複製,可以安全地傳遞或儲存。
context()
有些機制可以保護你,如果你讓內容持續存在於取得它的範圍之外。實際上你不應該依賴這些防護措施,而且它們會發出相當吵雜的警告。
你永遠不知道你從自己的工具中呼叫哪些工具需要內容。提早取得內容可確保巢狀工具可以找到你希望它們找到的內容。
請注意測試已完成。如果尚未設定計畫,這將產生計畫事件。
這將回傳一個淺層複製的內容。淺層複製可以安全地儲存以供稍後使用。
這將釋放內容。這會執行清理工作,以及幾個重要的掛勾。它也會將 $!
、$?
和 $@
還原為在建立內容時的值。
注意:如果內容被取得超過一次,會保留一個內部參考計數。release()
會遞減參考計數,除非參考計數達到 0,否則 release()
的其他動作都不會發生。這表示只有對 release()
的最後一次呼叫會重設 $?
、$!
、$@
,並執行清理工作。
這會拋出一個例外,報告內容的檔案和行號。這也會為你釋放內容。
這會從內容的檔案和行號發出警告。
這會回傳 Test2::API::Stack 執行個體,內容用來尋找目前的集線器。
這會回傳 Test2::Hub 執行個體,內容辨識為目前一個,所有事件都應傳送給它。
這會回傳 Test2::EventFacet::Trace 執行個體,內容使用它。
有時你有一個不是目前的內容,而且你想要使用它作為目前的內容。在這些情況下,你可以呼叫 $ctx->do_in_context(sub { ... })
。程式區塊將會執行,而且在其中尋找內容的任何東西都會找到呼叫該方法的內容。
這不會影響其他集線器上的內容,只有內容使用的集線器會受到影響。
my $ctx = ...;
$ctx->do_in_context(sub {
my $ctx = context(); # returns the $ctx the sub is called on
});
注意:內容實際上會被複製,複製會用來取代原始內容。這允許執行緒 ID、處理程序 ID 和錯誤變數正確,而不會修改原始內容。
這會將 $!
、$?
和 $@
設定為在建立內容時的值。這裡沒有本地化或任何動作,呼叫這個方法實際上會設定這些變數。
在建立內容時 $!
的(數字)值。
在建立內容時 $?
的值。
當建立內容時 $@
的值。
我該使用哪一個?
如果 pass*
和 fail*
符合你的情況,它們是最理想的選擇,使用其中一個總是最佳的選擇。話雖如此,它們會透過消除許多功能來達到最佳化。
例如 ok
和 note
等方法是根據舊 API 產生常見的 1 項任務事件的捷徑,但它們向前相容且易於使用。如果這些方法符合你的需求,請繼續使用它們,但請經常查看可能新增的替代方案。
如果你想產生新樣式的事件,一次執行多項任務的事件,那麼你會需要 *ev2*
方法。這些方法讓你直接指定你想要使用的方面。
這將傳送並傳回一個 Test2::Event::Pass 事件。你可以選擇為斷言提供一個 $name
。
Test2::Event::Pass 是特別製作且最佳化的事件,使用它將有助於通過測試的效能。
這是 pass()
和 release()
的組合。如果你不打算在傳送事件後對內容進行任何操作,則可以使用這個方法。這有助於撰寫更清晰且簡潔的程式碼。
sub shorthand {
my ($bool, $name) = @_;
my $ctx = context();
return $ctx->pass_and_release($name) if $bool;
... Handle a failure ...
}
sub longform {
my ($bool, $name) = @_;
my $ctx = context();
if ($bool) {
$ctx->pass($name);
$ctx->release;
return 1;
}
... Handle a failure ...
}
這讓你傳送 Test2::Event::Fail 事件。你可以選擇提供 $name
和 @diagnostics
訊息。
診斷訊息可以是簡單的字串、資料結構或 Test2::EventFacet::Info::Table 的實例(會內嵌轉換成 Test2::EventFacet::Info 結構)。
這是 fail()
和 release()
的組合。這可以用來撰寫更清晰、更簡短的程式碼。
sub shorthand {
my ($bool, $name) = @_;
my $ctx = context();
return $ctx->fail_and_release($name) unless $bool;
... Handle a success ...
}
sub longform {
my ($bool, $name) = @_;
my $ctx = context();
unless ($bool) {
$ctx->pass($name);
$ctx->release;
return 1;
}
... Handle a success ...
}
注意:不建議使用此方法,而建議使用 pass()
和 fail()
,它們會產生 Test2::Event::Pass 和 Test2::Event::Fail 事件。這些較新的事件類型速度較快,且較不雜亂。
這將為您建立一個 Test2::Event::Ok 物件。如果 $bool
為 false,則也會傳送一個 Test2::Event::Diag 事件,其中包含有關失敗的詳細資料。如果您不想要自動診斷,則應該直接使用 send_event()
方法。
第三個引數 \@on_fail
) 是在測試失敗時傳送的一組選用診斷。與 fail()
不同,這些診斷必須是純文字,不支援資料結構。
傳送 Test2::Event::Note。此事件會將訊息列印至 STDOUT。
傳送 Test2::Event::Diag。此事件會將訊息列印至 STDERR。
這可以用來傳送 Test2::Event::Plan 事件。此事件通常會採用您預期執行的測試數目。您也可以選擇將預期計數設定為 0,並提供 'SKIP' 指令和原因,以導致略過所有測試。
傳送 Test2::Event::Skip 事件。
這會傳送 Test2::Event::Bail 事件。此事件會完全終止所有測試。
這讓您可以直接從 facets 建立並傳送 V2 事件。事件在傳送後會傳回。
此範例傳送單一斷言、註解 (在 Test::Builder 中對 stdout 的註解) 並將計畫設定為 1。
my $event = $ctx->send_event(
plan => {count => 1},
assert => {pass => 1, details => "A passing assert"},
info => [{tag => 'NOTE', details => "This is a note"}],
);
這與 send_ev2()
相同,除了它會建立並傳回事件,而不會傳送事件。
這是 send_ev2()
和 release()
的組合。
sub shorthand {
my $ctx = context();
return $ctx->send_ev2_and_release(assert => {pass => 1, details => 'foo'});
}
sub longform {
my $ctx = context();
my $event = $ctx->send_ev2(assert => {pass => 1, details => 'foo'});
$ctx->release;
return $event;
}
在新程式碼中最好使用 send_ev2()。
這讓您可以建立並傳送任何類型的事件。$Type
參數應該是事件套件名稱,不包含 Test2::Event::
,或加上 '+' 前綴的完整限定套件名稱。事件在傳送後會傳回。
my $event = $ctx->send_event('Ok', ...);
或
my $event = $ctx->send_event('+Test2::Event::Ok', ...);
在新程式碼中最好使用 build_ev2()。
這與 send_event()
相同,除了它會建立並傳回事件,而不會傳送事件。
在新程式碼中最好使用 send_ev2_and_release()。
這是 send_event()
和 release()
的組合。
sub shorthand {
my $ctx = context();
return $ctx->send_event_and_release(Pass => { name => 'foo' });
}
sub longform {
my $ctx = context();
my $event = $ctx->send_event(Pass => { name => 'foo' });
$ctx->release;
return $event;
}
有 2 種鉤子,初始化鉤子和釋放鉤子。顧名思義,這些鉤子會在建立或釋放內容時觸發。
這些鉤子會在每次初始化內容時呼叫。這表示在建立新執行個體時。這些鉤子不會在每次有東西要求內容時呼叫,只會在建立新內容時呼叫。
以下是新增全域初始化回呼的方式。全域回呼會發生在任何 hub 或堆疊的每個內容。
Test2::API::test2_add_callback_context_init(sub {
my $ctx = shift;
...
});
以下是為給定 hub 建立的所有內容新增初始化回呼的方式。這些回呼不會在其他 hub 中執行。
$hub->add_context_init(sub {
my $ctx = shift;
...
});
以下是指定初始化鉤子的方式,它只會在呼叫 context()
產生新內容時執行。如果 context()
傳回現有內容,則會略過回呼。
my $ctx = context(on_init => sub {
my $ctx = shift;
...
});
這些鉤子會在每次釋放內容時呼叫。這表示在準備銷毀執行個體的最後一個參考時。這些鉤子不會在每次呼叫 $ctx->release
時呼叫。
以下是新增全域釋放回呼的方式。全域回呼會發生在任何 hub 或堆疊的每個內容。
Test2::API::test2_add_callback_context_release(sub {
my $ctx = shift;
...
});
以下是為給定 hub 建立的所有內容新增釋放回呼的方式。這些回呼不會在其他 hub 中執行。
$hub->add_context_release(sub {
my $ctx = shift;
...
});
以下是將釋放回呼直接新增到內容的方式。回呼永遠會新增到傳回的內容,不論是產生新內容或傳回現有內容。
my $ctx = context(on_release => sub {
my $ctx = shift;
...
});
這個物件使用 Test2::Util::ExternalMeta,它提供一致的方式讓您將元資料附加到這個類別的執行個體。這對工具、外掛程式和其他擴充套件很有用。
Test2 的原始碼存放庫位於 http://github.com/Test-More/test-more/。
著作權所有 2020 Chad Granum <exodist@cpan.org>。
本程式為自由軟體;您可以在與 Perl 相同的條款下重新散布或修改它。
請參閱 http://dev.perl.org/licenses/