內容

名稱

Test2::API - 撰寫 Test2 基礎測試工具的主要介面。

***內部注意事項***

此套件的內部結構隨時可能變更!提供的公開方法不會以向下不相容的方式變更 (一旦有穩定版本),但底層實作細節可能會變更。請勿在此處破壞封裝!

目前實作是建立 Test2::API::Instance 物件的單一執行個體。所有類別方法都遞延到單一執行個體。沒有公開存取單例,這是故意的。此套件提供的類別方法提供唯一公開的公開功能。

執行此項操作主要是為了避免 Test::Builder 公開其單例時遇到的問題。我們不希望任何人取代此單例、重新祝福它,或直接破壞其內部結構。如果您需要執行某些操作,但由於此處的限制而無法執行,請將其報告為問題。如果可能,我們將建立一種方法,讓您在不公開不應公開的事項的情況下實作您的功能。

說明

此套件匯出所有用於撰寫和/或驗證測試工具所需的功能。使用這些建構模組,您可以開始非常快速地撰寫測試工具。您還可以使用這些工具來測試您撰寫的工具。

SYNOPSIS

撰寫工具

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 文件,以取得如何最佳使用它的詳細資訊。

其他 API 功能

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 ...

主要 API 匯出

所有匯出都是選用的。您必須指定要匯入的子程式。

use Test2::API qw/context intercept run_subtest/;

這是最常需要的匯出清單。如果您只是在撰寫工具,那麼這可能是您唯一需要的。如果您需要一些東西,卻在此處找不到,那麼您也可以查看 "其他 API 匯出"

這些匯出由於其重要性/普遍性而沒有 'test2_' 前綴。"其他 API 匯出" 區段中的匯出具有 'test2_' 前綴,以確保它們顯著突出。

context(...)

用法

$ctx = context()
$ctx = context(%params)

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 的所有參數都是選用的。

level => $int

如果您必須在比進入點更深的子程式中取得內容,您可以使用這個參數告訴它回溯多少額外的堆疊框架。如果未提供此選項,則使用預設值 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;
});
wrapped => $int

如果您需要撰寫自己的工具來包裝對 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;
}

如果您沒有這樣做,那麼您呼叫的工具也會檢查內容,它們會注意到它們取得的內容是在相同的堆疊深度建立的,這會觸發保護措施,警告您並摧毀現有的內容。

stack => $stack

通常,context() 會查看全域 hub 堆疊。如果您正在維護自己的 Test2::API::Stack 執行個體,您可以傳遞它以用來取代全域執行個體。

hub => $hub

如果您想要取得特定 hub 的內容,而不是堆疊頂端的任何內容,請使用這個參數。

on_init => sub { ... }

這讓您可以提供一個回呼子程式,只有在您的 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;
}
on_release => sub { ... }

這可讓您提供一個回呼子,在釋放內容實例時會呼叫它。即使傳回現有的內容,也會將此回呼子新增至傳回的內容。如果呼叫內容多次新增回呼子,則在最後釋放內容時,所有回呼子都會按反向順序呼叫。

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;
}

release($;$)

用法

release $ctx;
release $ctx, ...;

這是一個捷徑,可讓您在一個陳述式中釋放內容並傳回一個值。此函式會取得您的內容,以及一個選用的傳回值。它會釋放您的內容,然後傳回您的值。它總是假設是純量內容。

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(...);

context_do(&;@)

用法

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.
    } @_;
}

在您的測試工具中使用此工具可為您處理許多樣板。它會確保取得內容。它會擷取並重新擲回任何例外。它會確保在您完成時釋放內容。它會保留子常式呼叫內容(陣列、純量、空值)。

這是撰寫測試工具最安全的方法。此方法僅有兩個缺點:效能略微下降,以及來源程式碼中會有一些額外的縮排。如果您覺得縮排有問題,可以看看下一部分。

no_context(&;$)

用法

no_context { ... };
no_context { ... } $hid;
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 參數。

intercept(&)

用法

my $events = intercept {
    ok(1, "pass");
    ok(0, "fail");
    ...
};

此函式將程式區塊作為其唯一引數,並具有原型。它將執行程式區塊,攔截過程中產生的任何事件。它將傳回一個包含所有已產生事件物件的陣列參考。所有事件都應該是 Test2::Event 的子類別。

從 1.302178 版開始,傳回的事件陣列會以 Test2::API::InterceptResult 執行個體的形式進行 blssed。 Test2::API::InterceptResult 提供一個有用的介面,用於過濾和/或檢查事件清單整體,或清單中的個別事件。

這旨在幫助您測試您的測試程式碼。這不適用於僅撰寫測試的人員。

run_subtest(...)

用法

run_subtest($NAME, \&CODE, $BUFFERED, @ARGS)

# or

run_subtest($NAME, \&CODE, \%PARAMS, @ARGS)

這將使用 @args 中的引數執行提供的程式區塊。此程式區塊將作為子測試執行。子測試是一個孤立的測試狀態,它濃縮成單一的 Test2::Event::Subtest 事件,其中包含在子測試中產生的所有事件。

引數

$NAME

子測試的名稱。

\&CODE

在子測試中執行的程式碼。

$BUFFERED 或 \%PARAMS

如果這是一個簡單的純量,則它將被視為 'buffered' 設定的布林值。如果這是一個雜湊參考,則它將被用作參數雜湊。參數雜湊將用於 hub 建構(移除指定的鍵)。

由 run_subtest 移除並使用的鍵

'buffered' => $bool

切換緩衝狀態。

'inherit_trace' => $bool

通常,子測試 hub 會被推入,並且子測試被允許為 hub 產生自己的根目錄內容。當此設定開啟時,將會為 hub 建立一個根目錄內容,與目前的內容共用相同的追蹤。

如果您的工具產生沒有使用者指定的子測試,請將此設定為 true。

'no_fork' => $bool

預設為關閉。通常在子測試中分岔實際上會分岔子測試,導致 2 個最終子測試事件。此參數將關閉該行為,只有原始程序/執行緒會傳回最終子測試事件。

@ARGS

您希望傳遞到子測試程式碼中的任何額外參數。

緩衝與非緩衝 (或串流)

通常,子測試內部和外部的所有事件都會由 hub 立即傳送給格式化程式。有時,最好等到子測試完成後才傳送事件。這通常取決於所使用的格式化程式。

不受此標記影響的事項

在兩種情況下,事件都會產生並儲存在陣列中。此陣列最終用於在子測試結束時產生的 Test2::Event::Subtest 事件中填入 subevents 屬性。此標記不會影響此部分,它總是會發生。

在子測試結束時,最終的 Test2::Event::Subtest 事件會傳送給格式化程式。

受此標記影響的事項

Test2::Event::Subtest 事件的 buffered 屬性會設定為此標記的值。這表示任何查看事件的格式化程式、監聽器等都會知道它是否已緩衝。

取決於格式化程式的項目

緩衝子測試中的事件可能會或可能不會在發生時傳送給格式化程式。如果格式化程式無法指定,則預設為不傳送事件,因為它們已產生,而格式化程式可以從 subevents 屬性中提取它們。

格式化程式可以透過實作 hide_buffered() 方法來指定。如果此方法傳回 true,則在緩衝子測試中產生的事件將不會獨立於最終子測試事件傳送。

這個用法的一個範例是 Test2::Formatter::TAP 格式化器。對於未緩衝的子測試,事件會在產生時呈現。在子測試結束時,會呈現最後的子測試事件,但會忽略 subevents 屬性。對於緩衝的子測試,會發生相反的情況,事件不會在產生時呈現,而是使用 subevents 屬性一次呈現所有事件。這在並行執行子測試時很有用,因為沒有這個屬性,子測試的輸出會交錯在一起。

其他 API 輸出

本節中的輸出通常不需要。這些輸出都加上 'test2_' 前綴,以確保它們脫穎而出。您應該先查看 "主要 API 輸出" 部分,再查看這裡。本部分是「能力越大,責任越大」的範例。如果您不謹慎使用這些輸出,可能會造成嚴重問題。

所有輸出都是選擇性的。您需要在匯入時列出您要使用的輸出

use Test2::API qw/test2_init_done .../;

狀態和初始化狀態

這些輸出提供對內部狀態和物件實例的存取權。

$bool = test2_init_done()

如果堆疊和 IPC 實例已經初始化,這個輸出會傳回 true。如果它們尚未初始化,這個輸出會傳回 false。初始化會在最晚的時候發生。它會在工具請求 IPC 實例、格式化器或堆疊時發生。

$bool = test2_load_done()

這個輸出會傳回 loaded 旗標的布林值。如果 Test2 已完成載入,這個輸出會傳回 true,否則會傳回 false。載入會在工具第一次請求內容時完成。

test2_set_is_end()
test2_set_is_end($bool)

這個輸出用於切換 Test2 認為 END 階段已經開始的信念。如果沒有參數,這個輸出會將其設定為 true。如果有參數,這個輸出會將其設定為第一個參數的值。

這用於防止在 END 區塊中使用 caller(),這可能會導致段落錯誤。這僅在可能有多個 END 階段的一些持續環境中需要。

$bool = test2_get_is_end()

檢查 Test2 是否認為這是 END 階段。

$stack = test2_stack()

這將傳回全域 Test2::API::Stack 執行個體。如果尚未初始化,現在將初始化。

$bool = test2_is_testing_done()

如果測試已完成且不應傳送其他事件,這將傳回 true。這在警告處理常式等項目中很有用,在這些項目中您可能想要將警告轉換為事件,但在測試完成時需要它們開始像正常警告一樣作用。

$SIG{__WARN__} = sub {
    my ($warning) = @_;

    if (test2_is_testing_done()) {
        warn @_;
    }
    else {
        my $ctx = context();
        ...
        $ctx->release
    }
}
test2_ipc_disable

停用 IPC。

$bool = test2_ipc_diabled

檢查 IPC 是否已停用。

test2_ipc_wait_enable()
test2_ipc_wait_disable()
$bool = test2_ipc_wait_enabled()

這些可用於開啟和關閉 IPC 等待,或檢查標記的目前值。

等待預設為開啟。等待將導致父處理程序/執行緒在退出前等待所有子處理程序和執行緒完成。您幾乎永遠都不會想要關閉這個功能。

$bool = test2_no_wait()
test2_no_wait($bool)

不建議:這是一個令人困惑的介面,最好使用 test2_ipc_wait_enable()test2_ipc_wait_disable()test2_ipc_wait_enabled()

這可用於取得/設定 no_wait 狀態。等待預設為開啟。等待將導致父處理程序/執行緒在退出前等待所有子處理程序和執行緒完成。您幾乎永遠都不會想要關閉這個功能。

$fh = test2_stdout()
$fh = test2_stderr()

這些函式傳回應寫入測試輸出的檔案控制代碼。它們主要在撰寫自訂格式化器和將事件轉換為實際輸出的程式碼(TAP 等)時很有用。它們將傳回格式化輸出可以傳送到的原始檔案控制代碼的重複,無論目前執行的測試可能將 STDOUT 和 STDERR 留在什麼狀態。

test2_reset_io()

重新複製 test2_stdout()test2_stderr() 從目前的 STDOUT 和 STDERR 回傳的內部檔案處理常式。除了在非常特殊的情況下,你不需要這麼做(例如,你正在測試一個新的格式化器,你需要控制格式化器將輸出傳送至何處。)

行為掛鉤

這些掛鉤允許你將自訂行為加入 Test2 和建立在其上的工具所執行的動作。

test2_add_callback_exit(sub { ... })

這可用於加入一個在所有測試完成後呼叫的回呼。這對於加入額外結果來說太遲了,此回呼的主要用途是設定結束代碼。

test2_add_callback_exit(
    sub {
        my ($context, $exit, \$new_exit) = @_;
        ...
    }
);

傳入的 $context 將會是 Test2::API::Context 的一個實例。$exit 參數將會是任何東西修改它之前的原始結束代碼。$$new_exit 是新結束代碼的參考。你可以修改它來變更結束代碼。請注意,$$new_exit 可能已經與 $exit 不同

test2_add_callback_post_load(sub { ... })

加入一個在 Test2 完成載入時將會呼叫的回呼。這表示回呼將會執行一次,在第一次取得內容時。如果 Test2 已經完成載入,則回呼將會立即執行。

test2_add_callback_testing_done(sub { ... })

這將你的代碼參考加入到 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
});
test2_add_callback_context_acquire(sub { ... })

新增一個回呼函式,每次有人嘗試取得內容時就會呼叫它。這會在每次呼叫 context() 時呼叫。它會取得一個單一參數,即用於建構內容的參數雜湊的參考。這時您可以直接變更雜湊來變更參數。

test2_add_callback_context_acquire(sub {
    my $params = shift;
    $params->{level}++;
});

這是一個非常可怕的 API 函式。除非您有需要,否則請勿使用。這是在 Test::Builder 和向後相容性中使用的。由於效能因素,這會讓您直接操作雜湊,而不是傳回新的雜湊。

test2_add_callback_context_init(sub { ... })

新增一個回呼函式,每次建立新的內容時就會呼叫它。回呼函式會將新建立的內容作為其唯一參數接收。

test2_add_callback_context_release(sub { ... })

新增一個回呼函式,每次釋放內容時就會呼叫它。回呼函式會將釋放的內容作為其唯一參數接收。

test2_add_callback_pre_subtest(sub { ... })

新增一個回呼函式,每次要執行子測試時就會呼叫它。回呼函式會接收子測試名稱、代碼參考和任何參數。

@list = test2_list_context_acquire_callbacks()

傳回所有內容取得回呼函式參考。

@list = test2_list_context_init_callbacks()

傳回所有內容初始化回呼函式參考。

@list = test2_list_context_release_callbacks()

傳回所有內容釋放回呼函式參考。

@list = test2_list_exit_callbacks()

傳回所有離開回呼函式參考。

@list = test2_list_post_load_callbacks()

傳回所有載入後回呼函式參考。

@list = test2_list_pre_subtest_callbacks()

傳回所有子測試前回呼函式參考。

test2_add_uuid_via(sub { ... })
$sub = test2_add_uuid_via()

這讓您可以提供 UUID 產生器。如果提供,UUID 會附加到所有事件、樞紐和內容。這對於儲存、追蹤和連結這些物件很有用。

您提供的子程式應始終傳回一個唯一的識別碼。大多數情況下會需要一個適當的 UUID 字串,但 Test2::API 中並未強制執行這項規定。

子程式將收到一個參數,即標記為「context」、「hub」或「event」的物件類型。未來可能會標記其他物件,屆時將傳入新的字串。這些純粹是提供資訊,您可以(且通常應該)忽略它們。

IPC AND CONCURRENCY

這些讓您可以存取或指定 IPC 系統內部元件。

$bool = test2_has_ipc()

檢查 IPC 是否已啟用。

$ipc = test2_ipc()

這將傳回全域 Test2::IPC::Driver 執行個體。如果尚未初始化,則現在會進行初始化。

test2_ipc_add_driver($DRIVER)

將 IPC 驅動程式新增至清單。這會將驅動程式新增至清單的開頭。

@drivers = test2_ipc_drivers()

取得 IPC 驅動程式的清單。

$bool = test2_ipc_polling()

檢查是否已啟用輪詢。

test2_ipc_enable_polling()

開啟輪詢。每次建立 context 時,這會從其他程序和執行緒中刪除事件。

test2_ipc_disable_polling()

關閉 IPC 輪詢。

test2_ipc_enable_shm()

舊版,目前這是一個無操作的 no-op,會傳回 0;

test2_ipc_set_pending($uniq_val)

告訴其他程序和事件有一個事件正在處理中。$uniq_val 應為唯一值,不會由其他執行緒/程序產生。

注意:呼叫此函式後,test2_ipc_get_pending() 會傳回 1。這是故意的,無法避免。

$pending = test2_ipc_get_pending()

如果沒有辦法檢查(假設為是),則傳回 -1

如果(很可能)沒有待處理事件,這會傳回 0。

如果(很可能)有待處理事件,這會傳回 1。傳回後它會重設,沒有其他東西能看到有待處理事件。

$timeout = test2_ipc_get_timeout()
test2_ipc_set_timeout($timeout)

取得/設定 IPC 系統的逾時值。這個逾時值是 IPC 系統在中止子行程和執行緒之前,會等待它們完成的時間長度。

預設值是 30 秒。

管理格式器

這些讓您可以存取或指定可以/應該使用的格式器。

$formatter = test2_formatter

這會傳回全域格式器類別。這不是一個執行個體。預設情況下,格式器設定為 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
test2_formatter_set($class_or_instance)

設定全域格式器類別。這只能設定一次。注意:這會覆寫 'T2_FORMATTER' 環境變數中指定的所有內容。

@formatters = test2_formatters()

取得所有已載入格式器的清單。

test2_formatter_add($class_or_instance)

將一個格式器加入清單。最後加入的格式器會在初始化時使用。如果在初始化後呼叫這個,會發出一個警告。

其他範例

請參閱此發行版中包含的 /Examples/ 目錄。

另請參閱

Test2::API::Context - 內容物件的詳細文件。

Test2::IPC - 用於執行緒/分岔支援的 IPC 系統。

Test2::Formatter - 格式器,例如 TAP,存在於此處。

Test2::Event - 事件存在於這個命名空間中。

Test2::Hub - 所有事件最終會透過一個集線器傳遞。自訂集線器是 intercept()run_subtest() 的實作方式。

MAGIC

這個套件有一個 END 函式區塊。這個 END 函式區塊負責根據測試結果設定結束代碼。這個結束函式區塊也會呼叫可以新增到這個套件的回呼函式。

SOURCE

Test2 的原始碼儲存庫可以在 http://github.com/Test-More/test-more/ 找到。

MAINTAINERS

Chad Granum <exodist@cpan.org>

AUTHORS

Chad Granum <exodist@cpan.org>

COPYRIGHT

版權所有 2020 Chad Granum <exodist@cpan.org>。

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

請參閱 http://dev.perl.org/licenses/