內容

名稱

TAP::Parser - 分析 TAP 輸出

版本

版本 3.44

概要

use TAP::Parser;

my $parser = TAP::Parser->new( { source => $source } );

while ( my $result = $parser->next ) {
    print $result->as_string;
}

說明

TAP::Parser 旨在正確分析 TAP 輸出。如需瞭解如何透過此模組執行測試的範例,請參閱簡單的範例程式碼 examples/

有一個專門的 Wiki 網站介紹 Test Anything Protocol

http://testanything.org

其中包含 TAP::Parser 食譜

http://testanything.org/testing-with-tap/perl/tap::parser-cookbook.html

方法

類別方法

new

my $parser = TAP::Parser->new(\%args);

傳回新的 TAP::Parser 物件。

參數應為雜湊參照,其中包含下列 其中一個

下列金鑰是選用的。

實例方法

next

my $parser = TAP::Parser->new( { source => $file } );
while ( my $result = $parser->next ) {
    print $result->as_string, "\n";
}

此方法會一次傳回一個剖析結果。請注意,此方法具有破壞性。您無法倒帶並檢查先前的結果。

如果使用回呼,則會在此呼叫傳回之前發出回呼。

傳回的每個結果都是 TAP::Parser::Result 的子類別。請參閱該模組和相關類別,以取得如何使用它們的更多資訊。

run

$parser->run;

此方法只會執行剖析器並剖析所有 TAP。

make_grammar

建立新的 TAP::Parser::Grammar 物件並傳回。傳遞任何給定的引數。

grammar_class 可以自訂,如 "new" 中所述。

make_result

使用剖析器的 TAP::Parser::ResultFactory 建立新的 TAP::Parser::Result 物件,並傳回。傳遞任何給定的引數。

result_factory_class 可以自訂,如 "new" 中所述。

make_iterator_factory

3.18 新增.

建立新的 TAP::Parser::IteratorFactory 物件並傳回。傳遞任何給定的引數。

iterator_factory_class 可以自訂,如 "new" 中所述。

個別結果

如果您已經讀到文件中的這裡,您會看到這個

while ( my $result = $parser->next ) {
    print $result->as_string;
}

傳回的每個結果都是 TAP::Parser::Result 子類別,稱為結果類型

結果類型

基本上,您可以從 TAP 中擷取個別結果。六種類型,每個類型都有範例,如下所示

擷取的每個結果都是不同類型的結果物件。每個結果物件都有共用方法,而不同類型可能有其類型獨有的方法。有時類型方法可能會在子類別中覆寫,但保證其使用方式相同。

共用類型方法

type

傳回結果類型,例如 commenttest

as_string

列印標記的字串表示形式。不過,這可能不是確切的輸出。如果測試沒有數字,則會加上測試數字,TODO 和 SKIP 指令會變成大寫,而且一般來說,會將內容清理乾淨。如果您需要標記的原始文字,請參閱 raw 方法。

raw

傳回已分析的原始文字列。

is_plan

指出這是否是測試計畫列。

is_test

指出這是否是測試列。

is_comment

指出這是否是註解。如果 STDERR 已合併到 STDOUT,註解通常只會出現在 TAP 串流中。請參閱 merge 選項。

is_bailout

指出這是否是退出列。

is_yaml

指出目前的項目是否是 YAML 區塊。

is_unknown

指出目前的列是否可以分析。

is_ok

if ( $result->is_ok ) { ... }

報告給定的結果是否已通過。任何不是測試結果的項目都會傳回 true。這僅提供一個方便的捷徑,讓您可以執行此操作

my $parser = TAP::Parser->new( { source => $source } );
while ( my $result = $parser->next ) {
    # only print failing results
    print $result->as_string unless $result->is_ok;
}

plan 方法

if ( $result->is_plan ) { ... }

如果上述評估為真,則下列方法將在 $result 物件上提供。

plan

if ( $result->is_plan ) {
   print $result->plan;
}

這只不過是 as_string 的同義詞。

directive

my $directive = $result->directive;

如果 SKIP 指令包含在計畫中,這個方法將會傳回它。

1..0 # SKIP: why bother?

explanation

my $explanation = $result->explanation;

如果 SKIP 指令包含在計畫中,這個方法將會傳回說明,如果有的話。

pragma 方法

if ( $result->is_pragma ) { ... }

如果上述評估為真,則下列方法將在 $result 物件上提供。

pragmas

傳回指令清單,每個指令清單都是 + 或 -,後面接著指令名稱。

comment 方法

if ( $result->is_comment ) { ... }

如果上述評估為真,則下列方法將在 $result 物件上提供。

comment

if ( $result->is_comment ) {
    my $comment = $result->comment;
    print "I have something to say:  $comment";
}

bailout 方法

if ( $result->is_bailout ) { ... }

如果上述評估為真,則下列方法將在 $result 物件上提供。

explanation

if ( $result->is_bailout ) {
    my $explanation = $result->explanation;
    print "We bailed out because ($explanation)";
}

如果且僅當一個代幣是救援代幣時,你可以透過這個方法取得「說明」。說明是出現在 tap 輸出中神秘的「Bail out!」字詞之後的文字。

unknown 方法

if ( $result->is_unknown ) { ... }

沒有針對未知結果的獨特方法。

test 方法

if ( $result->is_test ) { ... }

如果上述評估為真,則下列方法將在 $result 物件上提供。

ok

my $ok = $result->ok;

傳回 oknot ok 狀態的文字。

number

my $test_number = $result->number;

傳回測試的編號,即使原始的 TAP 輸出沒有提供該編號。

description

my $description = $result->description;

傳回測試的說明,如果有的話。這是測試編號之後但指令之前的部分。

directive

my $directive = $result->directive;

如果測試行有任何指令,傳回 TODOSKIP

explanation

my $explanation = $result->explanation;

如果測試有任何 TODOSKIP 指令,這個方法將會傳回隨附的說明,如果有的話。

not ok 17 - 'Pigs can fly' # TODO not enough acid

對於上述行,解釋為酸度不足

is_ok

if ( $result->is_ok ) { ... }

傳回一個布林值,指出測試是否通過。請記住,對於 TODO 測試,測試總是通過。

注意:這以前是passed。後者方法已棄用,並會發出警告。

is_actual_ok

if ( $result->is_actual_ok ) { ... }

傳回一個布林值,指出測試是否通過,不論其 TODO 狀態為何。

注意:這以前是actual_passed。後者方法已棄用,並會發出警告。

is_unplanned

if ( $test->is_unplanned ) { ... }

如果測試編號大於已規劃測試的數量,此方法會傳回 true。未規劃測試對於is_ok總是會傳回 false,不論測試是否有has_todo(有關此項目的更多資訊,請參閱TAP::Parser::Result::Test)。

has_skip

if ( $result->has_skip ) { ... }

傳回一個布林值,指出此測試是否具有 SKIP 指令。

has_todo

if ( $result->has_todo ) { ... }

傳回一個布林值,指出此測試是否具有 TODO 指令。

請注意,TODO 測試總是通過。如果您需要知道它們是否真的通過,請檢查is_actual_ok方法。

in_todo

if ( $parser->in_todo ) { ... }

在最近的結果為 TODO 時為 True。在傳回 TODO 結果之前變為 True,並在傳回下一個非 TODO 測試之前保持為 True。

總計結果

在分析 TAP 之後,有許多方法可讓您深入探討結果,並決定對您有意義的內容。

個別結果

這些結果是指執行個別測試。

passed

my @passed = $parser->passed; # the test numbers which passed
my $passed = $parser->passed; # the number of tests which passed

此方法讓您知道哪些(或多少)測試通過。如果測試失敗,但有 TODO 指令,則會將其計為通過測試。

failed

my @failed = $parser->failed; # the test numbers which failed
my $failed = $parser->failed; # the number of tests which failed

此方法讓您知道哪些(或多少)測試失敗。如果測試通過,但有 TODO 指令,則不會將其計為失敗測試。

actual_passed

# the test numbers which actually passed
my @actual_passed = $parser->actual_passed;

# the number of tests which actually passed
my $actual_passed = $parser->actual_passed;

此方法讓您知道哪些(或多少)測試實際上通過,不論是否找到 TODO 指令。

actual_ok

此方法是 actual_passed 的同義詞。

actual_failed

# the test numbers which actually failed
my @actual_failed = $parser->actual_failed;

# the number of tests which actually failed
my $actual_failed = $parser->actual_failed;

此方法讓您知道哪些(或多少)測試實際上失敗,無論是否找到 TODO 指令。

todo

my @todo = $parser->todo; # the test numbers with todo directives
my $todo = $parser->todo; # the number of tests with todo directives

此方法讓您知道哪些(或多少)測試有 TODO 指令。

todo_passed

# the test numbers which unexpectedly succeeded
my @todo_passed = $parser->todo_passed;

# the number of tests which unexpectedly succeeded
my $todo_passed = $parser->todo_passed;

此方法讓您知道哪些(或多少)測試實際上通過,但被宣告為「TODO」測試。

todo_failed

# deprecated in favor of 'todo_passed'.  This method was horribly misnamed.

這是一個命名不當的方法。它指出哪些 TODO 測試意外成功。現在將發出警告並呼叫 todo_passed

skipped

my @skipped = $parser->skipped; # the test numbers with SKIP directives
my $skipped = $parser->skipped; # the number of tests with SKIP directives

此方法讓您知道哪些(或多少)測試有 SKIP 指令。

Pragmas

pragma

取得或設定 pragma。若要取得 pragma 的狀態

if ( $p->pragma('strict') ) {
    # be strict
}

若要設定 pragma 的狀態

$p->pragma('strict', 1); # enable strict mode

pragmas

取得目前已啟用 pragma 的清單

my @pragmas_enabled = $p->pragmas;

摘要結果

這些結果是關於個別測試程式總結果的「後設」資訊。

plan

my $plan = $parser->plan;

如果找到,傳回測試計畫。

good_plan

已過時。請改用 is_good_plan

is_good_plan

if ( $parser->is_good_plan ) { ... }

傳回布林值,指出計畫的測試數量是否與執行的測試數量相符。

注意:這以前是 good_plan。後者方法已過時,將發出警告。

既然我們在討論這個主題...

tests_planned

print $parser->tests_planned;

根據計畫,傳回計畫的測試數量。例如,計畫為「1..17」表示計畫了 17 個測試。

tests_run

print $parser->tests_run;

傳回實際執行的測試數量。希望這會與 $parser->tests_planned 的數量相符。

skip_all

如果所有測試都略過,傳回真值(實際上是略過的理由)。

start_time

傳回建立剖析器時的牆上時鐘時間。

end_time

傳回看到 TAP 輸入結束時的牆上時鐘時間。

start_times

傳回建立剖析器時的 CPU 時間(例如 "times" in perlfunc)。

end_times

傳回看到 TAP 輸入結束時的 CPU 時間(例如 "times" in perlfunc)。

has_problems

if ( $parser->has_problems ) {
    ...
}

這是一個「萬用」方法,如果任何測試目前失敗、任何 TODO 測試意外成功,或發生任何剖析錯誤,則傳回 true。

version

$parser->version;

剖析器完成後,這將傳回剖析 TAP 的版本號碼。版本號碼在 TAP 版本 13 中引入,因此如果找不到版本號碼,則假設為版本 12。

exit

$parser->exit;

剖析器完成後,這將傳回結束狀態。如果剖析器執行可執行檔,則傳回可執行檔的結束狀態。

wait

$parser->wait;

剖析器完成後,這將傳回等待狀態。如果剖析器執行可執行檔,則傳回可執行檔的等待狀態。否則,這只會傳回 exit 狀態。

ignore_exit

$parser->ignore_exit(1);

在決定測試是否通過時,告訴剖析器忽略測試的結束狀態。通常,即使所有個別測試都通過,但具有非零結束狀態的測試仍會被視為失敗。在無法控制測試腳本的結束值的情況下,請使用此選項來忽略它。

parse_errors

my @errors = $parser->parse_errors; # the parser errors
my $errors = $parser->parse_errors; # the number of parser_errors

幸運的是,所有 TAP 輸出都是完美的。如果並非如此,這個方法將傳回剖析器錯誤。請注意,剖析器無法辨識的垃圾行 不是 錯誤。這允許此剖析器處理 TAP 的未來版本。以下是剖析器報告的所有 TAP 錯誤

get_select_handles

取得檔案處理序清單,可以傳遞給 select 以確定此剖析器的準備狀態。

delete_spool

刪除並傳回暫存區。

my $fh = $parser->delete_spool;

CALLBACKS

如前所述,可以將「callback」金鑰新增到 TAP::Parser 建構函式中。如果存在,每個對應於特定結果類型的 callback 都會以結果作為引數呼叫,如果使用 run 方法。預期 callback 是子常式參考(或匿名子常式),並以剖析器結果作為其引數呼叫。

my %callbacks = (
    test    => \&test_callback,
    plan    => \&plan_callback,
    comment => \&comment_callback,
    bailout => \&bailout_callback,
    unknown => \&unknown_callback,
);

my $aggregator = TAP::Parser::Aggregator->new;
for my $file ( @test_files ) {
    my $parser = TAP::Parser->new(
        {
            source    => $file,
            callbacks => \%callbacks,
        }
    );
    $parser->run;
    $aggregator->add( $file, $parser );
}

也可以這樣新增 callback

$parser->callback( test => \&test_callback );
$parser->callback( plan => \&plan_callback );

允許 callback 的以下金鑰。這些金鑰區分大小寫。

TAP 語法

如果您正在尋找 EBNF 語法,請參閱 TAP::Parser::Grammar

向後相容性

Perl-QA 清單嘗試確保與 Test::Harness 向後相容。但是,有一些細微的差異。

差異

子類化

如果您發現需要提供自訂功能(就像使用 Test::Harness::Straps 一樣),您很幸運:TAP::Parser 和相關元件的設計很容易插入和/或子類化。

在開始之前,請務必了解幾件事

  1. 所有 TAP::* 物件都繼承自 TAP::Object

  2. 許多 TAP::* 類別都有子類化區段來指導您。

  3. 請注意,TAP::Parser 的設計是作為中央「製造者」,也就是說,它負責建立 TAP::Parser::* 名稱空間中的大多數新物件。

    這讓您可以單一設定要使用的子類別,這表示在許多情況下,您會發現您只需要子類化解析器的其中一個元件。

    此規則的例外是SourceHandlersIterators,但它們都是使用可自訂的IteratorFactory 建立的。

  4. 透過子類化,您可能會覆寫未記錄的方法。這本身不是壞事,但請注意,未記錄的方法可能會在不同版本之間不經警告地變更,我們無法保證向後相容性。如果需要變更任何已記錄的方法,它會先被標示為不建議使用,然後在後續版本中變更。

解析器元件

來源

TAP 解析器會使用單一 TAP原始來源的輸入,它可以來自任何地方(檔案、可執行檔、資料庫、IO 處理、URI 等)。來源會打包在 TAP::Parser::Source 物件中,它會收集一些關於來源的元資料。然後,解析器會使用 TAP::Parser::IteratorFactory 來決定要使用哪個 TAP::Parser::SourceHandler,透過 "Iterators" 將原始來源轉換為 TAP 串流。

如果您只是想讓 TAP::Parser 處理新的 TAP 來源,您可能不需要子類化 TAP::Parser 本身。相反地,您需要建立新的 TAP::Parser::SourceHandler 類別,並使用sources 參數將它插入解析器中,參數為 "new"。在開始撰寫之前,請先閱讀 TAP::Parser::IteratorFactory,以了解系統運作的方式。

如果您發現您真的需要使用您自己的迭代器工廠,您仍然可以在不子類別化 TAP::Parser 的情況下透過設定 "iterator_factory_class" 來進行。

如果您僅需要在建立時自訂物件,請子類別化 TAP::Parser 並覆寫 "make_iterator_factory"

請注意,make_sourcemake_perl_source 已被標示為過時,並已移除。

迭代器

TAP 解析器使用迭代器來迴圈讀取從來源讀取的 TAP 串流。預設提供幾種類型的迭代器,全部都是 TAP::Parser::Iterator 的子類別。選擇使用哪個迭代器是迭代器工廠的責任,儘管它僅委派給它使用的來源處理常式

如果您正在撰寫您自己的 TAP::Parser::SourceHandler,您可能也需要建立您自己的迭代器。如果是這樣,您需要子類別化 TAP::Parser::Iterator

請注意,"make_iterator" 已被標示為過時,並已移除。

結果

TAP 解析器在迴圈讀取輸入串流時會建立 TAP::Parser::Result。提供相當多的結果類型;選擇使用哪個類別是結果工廠的責任。

若要建立您自己的結果類型,您有兩個選項

選項 1

子類別化 TAP::Parser::Result 並將您的新結果類型/類別註冊到預設的 TAP::Parser::ResultFactory

選項 2

子類別化 TAP::Parser::ResultFactory 本身並實作您自己的 TAP::Parser::Result 建立邏輯。然後,您需要透過設定 result_factory_class 參數來自訂您的解析器所使用的類別。請參閱 "new" 以取得更多詳細資訊。

如果您需要在建立時自訂物件,請子類別化 TAP::Parser 並覆寫 "make_result"

語法

TAP::Parser::Grammar 是解析器的核心。它將 TAP 輸入串流進行標記化並產生結果。如果您需要自訂其行為,您應該先熟悉來源。足夠的說教了。

子類別化 TAP::Parser::Grammar 並透過設定 grammar_class 參數來自訂您的解析器。請參閱 "new" 以取得更多詳細資訊。

如果您需要在建立時自訂物件,請子類別化 TAP::Parser 並覆寫 "make_grammar"

致謝

以下所有人均提供協助。錯誤回報、修補程式、(不)道德支援或僅是鼓勵的話語,都已陸續收到。

作者

Curtis "Ovid" Poe <ovid@cpan.org>

Andy Armstong <andy@hexten.net>

Eric Wilhelm @ <ewilhelm at cpan dot org>

Michael Peters <mpeters at plusthree dot com>

Leif Eriksen <leif dot eriksen at bigpond dot com>

Steve Purkis <spurkis@cpan.org>

Nicholas Clark <nick@ccl4.org>

Lee Johnson <notfadeaway at btinternet dot com>

Philippe Bruhat <book@cpan.org>

錯誤

請將任何錯誤或功能要求回報至 bug-test-harness@rt.cpan.org,或透過 http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness 上的網路介面。我們會收到通知,然後當我們進行變更時,您會自動收到錯誤進度的通知。

顯然地,包含修補程式的錯誤是最好的。如果您願意,您可以透過匿名檢出最新版本來針對 bleed 進行修補

git clone git://github.com/Perl-Toolchain-Gang/Test-Harness.git

版權和授權

版權所有 2006-2008 Curtis "Ovid" Poe,保留所有權利。

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