北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

TAP::Harnessの出力をPerlから使う

CPANTest::TAP::Modelと言うクラスがあったけど、DEPRECATEDになっていたので、似たようなモジュールであるTAP::Formatter::RawDataを作ってみました。

使い方

使い方はこんな感じです。CPANには上げてないのでgithubのを使って下さい。かなり新しめのTest-Harness(3.15以上)が必要です。

use strict;
use warnings;
use TAP::Harness;
use TAP::Formatter::RawData;

# テスト実行
my $formatter = TAP::Formatter::RawData->new;
my $harness = TAP::Harness->new({
	formatter => $formatter,
	merge     => 1,  # if you want to record comments.
});

$harness->runtests(@ARGV);
# you can do also: my $aggregator = $harness->runtests(@ARGV); 

# 結果を取り出す
my $record     = $formatter->record;
# see TAP::Parser::Aggregator
my $aggregator = $record->aggregator;

for my $testname ( $aggregator->descriptions ){
	# see TAP::Parser
	my ( $parser ) = $aggregator->parsers($testname);  
	print "script: " , $testname, "\n";
	print "results: ", ($parser->has_problems ? 'NG' : 'OK'), "\n";
	print "comments: \n";
	# see TAP::Parser::Result
	for my $result ( $record->results($testname) ){
		next unless $result->is_comment;
		print $result->as_string, "\n";
	}
	print '-' x 79, "\n";
}
__END__

↓以下、実行結果

script: t/foo.t
results: OK
comments: 
# $VAR1 = {
#           'hage' => [
#                       'I am not Hage!!'
#                     ],
#           'hoge' => 1
#         };
-------------------------------------------------------------------------------
script: t/hoge.t
results: NG
comments: 
# this is comment
#   Failed test 'test d'
#   at t/hoge.t line 7.
#          got: 'a'
#     expected: 'd'
# Looks like you failed 1 test of 4.
-------------------------------------------------------------------------------
備考

このモジュールを使って嬉しいのは、TAPの全行(特にコメント)をPerlオブジェクトとして拾えること( $formatter->record->results($testname) )です。

サマリだけしか必要ないなら、AggregatorとParserのインスタンスはTAP::Harnessの枠組みで入手可能なのでこのモジュールは要りません。

実装

さっきのエントリによれば、FormatterとFormatter::Sessionを用意すればよし、と。

これだけ。

反省点

テスト結果データの取り出し時、中途半端にTAP::Parser::Aggregator と TAP::Parser を使わなければならないので、統一性がなくて気持ち悪いインタフェースになってます*1。全部 TAP::Formatter::RawData::Record に隠蔽した方がきれいになるかも。

*1:スクリプトのサマリがTAP::Parser、全体のサマリがTAP::Parser::Aggregator内にあるため