Hatena::Groupcside

Cside::StudyMemo このページをアンテナに追加 RSSフィード

メインブログに書くまでもない自分用メモを垂れ流す。日々是勉強也。

カテゴリー

2011-03-17

[][]よく使いそうなテスト用関数とか

書き途中・・・

テストに便利そうなモジュール

Proc::Guard

ttp://frepan.org/~tokuhirom/Proc-Guard-0.05/lib/Proc/Guard.pm

use Test::TCP qw/empty_port wait_port/;
use File::Which qw/which/;
use Proc::Guard;

my $port = empty_port();
my $proc = proc_guard(scalar(which('memcached')), '-p', $port);  # plackupとかでももちろん可
wait_port($port);  # 立ち上がるまで待つ

# your code here

# --------------
# or, use perl code
my $proc = proc_guard(sub {
    ... # run this code in child process
});
...

作成っとくと便利そうな関数とか

ttp://d.hatena.ne.jp/tori243/20110211

use Proc::Guard;
use Plack::Util;

sub start_plackup {
    my $self = shift;
    my %args = @_;
    my $app  = $args{app};
    my $port = $args{port} || Test::TCP::empty_port();
    my $envd  = $args{envd} || 'deployment';
    my @proc = (
        plackup =>
            (map { ( "-I" => $_ ) } @INC),
             '-p' => $port,
             '-a' => $app,
             '-E' => $envd,
    );
    Proc::Guard::proc_guard(@proc);
}

Test::WWW::Mechanize::*

use Test::WWW::Mechanize::PSGI

my $mech = Test::WWW::Mechanize::PSGI->new(app => $app);
{
    my $uri = "/api?num=5";
    $mech->get_ok($uri);
    $mech->head_ok($uri, ['Content-Type' => 'text/html']);
    $mech->content_like( qr/<<<25>>>/, '5の2乗が返ってくるはず');
}
DBD::Mock
Test::mysqld

2011-03-01

[][]Perlのテスト、あれこれ

subtest

似たようなケースが頻出するわりに、抽象化するのが面倒だし、わけわからなくなること必至であり、かつまた、こんなものを複数のファイルにわけていてはメンテナンスが面倒なことは考えるまでもない。

チミチミと似たような数行のテストをかいたファイルを複数つくるぐらいならば、このように subtest の利用を考えるべきだとおもう。

http://d.hatena.ne.jp/tokuhirom/20100118/1263800343
use Test::More;
subtest "testname1" => sub {
    #  ... test ...
    done_testing;
};

subtest "testname2" => sub {
    #  ... test ...
    done_testing;
};

done_testing;

done_testing

plan の逆っていうか plan で数を書くのめんどいじゃんすか

でも、plan 書かないと、テストが最後までうごいたかわからんから、no_plan とか書いてると信頼性に欠ける。

途中で exit したりしたら、success になっちゃうから。

だから、no_plan とか先頭で書くかわりに、オケツに done_testing 書いた方がいい というためのもの。

http://d.hatena.ne.jp/tokuhirom/20090706/1246861746

あと、ブロック内でskip_allも使える。

オブジェクト作成にはnew_ok

require Foo;
my $obj = new_ok("Foo");
# ... use $obj in testing ...
http://slashdot.jp/~taro-nishino/journal/524390

2011-02-27

[][]テストをデバッグしやすくする

テストを関数化する際の工夫

テストを関数化するのはよくあることだけれど、Test::Moreの場合、テストがこけたときに表示される行番号は共通関数の場所。これは嬉しくない。落ちる原因になった引数を定義している行番号を表示させるためには、$Test::Builder::Level の値を変えればよい。

use strict;
use Test::More;

sub bar {
	local $Test::Builder::Level = $Test::Builder::Level + 1;
	ok($_[0]);
}

sub foo {
	local $Test::Builder::Level = $Test::Builder::Level + 1;
	ok($_[0]);
	bar($_[0]);
}

foo(0);

done_testing();

ループをあえて展開する

for (@DATASETS) {
	test_func($_);  # どれがこけたのか分かりにくい!
}

繰り返し処理はループにするとデバッグしにくくなる。なので、あえてループを使わずに同じような処理をベタ書きするのも全然あり。

caller()

関数がどの(パッケージ|ファイル|行 )から呼ばれたかは、caller()で取得できる。引数は「いくつ前のコールスタックの内容を取るか(0は直前)」。

sub baz {
	my ($package, $filename, $line) = caller(0);
	print "callerd from $package [$filename at line $line]\n";
}
モダンPerl入門 (CodeZine BOOKS)

モダンPerl入門 (CodeZine BOOKS)

[][]Apache::Test - テスト起動時にApacheの面倒も見てくれるようにする

主な機能

  • 設定ファイル等の自動生成(Apache設定ファイルを含む)
  • Apacheの起動・停止
  • HTTPリクエストサイクルの動作確認ツール
  • .tファイルの実行

Apache::Testを使う場合のMakefile.PL

use strict;
use ExtUtils::MakeMaker;  # Module::Installの裏方

# おまじない
use Apache::TestMM qw/test clean/;  # make test と make clean をオーバーライド
Apache::TestMM::filter_args();
Apache::TestMM::generate_script('t/TEST');

my %INFO = (
	AUTHOR => 'NAME',
	DISTNAME => 'MyApp::MyModule',
	NAME => 'MyApp::MyModule',
	PREREQ_PM => {
		'Dependent::Module',
	},
	VIRSION_FROM => 'lib/MyApp/MyModule.pm',
);

WriteMakefile(%INFO);

t/TEST.PL

use Apache::TestRunPerl;
Apache::TestRunPerl->new->run(@ARGV);

設定ファイル

perl Makefile.PL && make && sudo make test すると以下のファイル類が自動生成される。

t/conf
t/conf/apache_test_config.pm
t/conf/httpd.conf
t/conf/modperl_inc.pl
t/conf/modperl_startup.pl

httpd.confはmake testのたびに上書きされてしまうので、追加の変更はextra.conf,inに書いておく。

# t/conf/extra.conf.in
# 例:/cgi-bin/test.cgiにアクセスして結果を見たい場合
ScriptAlias /cgi-bin/ @Top_Dir@/cgi-bin/
<Location /cgi-bin/>
	SetEnv PERL5OPT -Mblib=@Top_Dir@/blib
</Location>

Apache::Testでのテストの書き方

plan()でテストに必要な条件を細かく指定できる

use Apache::Test qw/-withtestmore/;
plan tests => 5,
     need_min_apache_version("2.0.40") &&
     need_cgi &&
     need_ssl &&
     need_min_perl_version("5.008001")
;

Apache::TestRequest

use Apache::TestRequest 'GET';
use Test::More;

my $url = "/cgi-bin/test.cgi";
my $body = GET($url)->content;
ok($body);

done_testing();

Apache::TestUtil

広い範囲をカバーするユーティリティ関数を備えているので複雑なテストを書く場合に便利。

use Apache::TestUtil qw/t_cmp/;
use Test::More;

# t_cmp() : is(), is_deeply(), like() を合成したような関数
ok t_cmp($value, 1);
ok t_cmp($value, undef);
ok t_cmp($value, qr/^a/);
ok t_cmp($value, { a=> 1, b => 2 });

# t_write_file() : 指定したファイル名の出力に必要なディレクトリがあれば作成。テスト終了時にファイルは自動で削除。
ok t_write_file($filename, "内容");

done_testing;
# ./t/TEST -verboseなどで実行すると、構造体をdumpした出力をしてくれる

Apache::TestRequest - search.cpan.org

mod_perlテスト

メモ途中....

モダンPerl入門 (CodeZine BOOKS)

モダンPerl入門 (CodeZine BOOKS)

no title

2011-02-26

[][]テストのキホンのキホン

テストファイルの指定

Makefile.PLで明示的にテストを指定しない場合は t/ 直下の .t で終わるファイルをテストファルとして認識してくれる。

ただ、 t/ 以下のサブディレクトリについては再帰的に探してくれないので明示的に指定する。

use inc::Module::Install;

test('t/*.t t/*/*/*.t');

頻繁に使うTest::Moreの関数

ok($true_or_false);
use_ok($class, @args);
require_ok($class_or_file);
isa_ok($object, 'クラス名');
can_ok($class, @methods);
is($value, '期待値');
isnt($value, '期待しない値');
like($value, qr/正規表現/)
unlike($value, qr/正規表現/)
is_deeply($value, { '構造体' });

テストフローの制御

テストがその環境で無効な場合はSKIP、テストがバグ等の吉の問題で落ちることが分かっている場合はTODO

TODO: {
    todo_skip(
        todo_skip("理由", $number_of_skip_tests);
    )
    # ここには到達しない
    ok( .... );
}
SKIP: {
    if ($^0 eq 'MSWin32') {
        skip("理由", $number_of_skip_tests);
    }
    ok( .... );
}

テストスクリプト全体をスキップする場合

use Test::More;
if ($^0 eq 'MSWin32') {
    plan(skip_all => 'このスクリプトはWinでは無効');
} else {
    plan(tests => 30);
}

テスト中のデバッグ方法

diag()はどんなときでも表示される。

note()はmake test時には表示されず、prove -vした時や直接テストファイルを実行した場合に表示される。

スカラー以外の構造体を出力するときはexplain。

is_deeply($hash, $expect)
    or diag( explain($hash) );

テストパターン

  1. 正常ケース
    • 正しい値を渡すケース
  2. エラーケース
    • 例えば整数値を処理する機能であれば、小数点数を渡したケースなど
  3. 限界ケース
    • 上限を超えた・下限を超えたケース
  4. 特殊ケース
    • undefを渡したケースなど

テスト出力における日本語の扱い

テスト出力は内部文字列を自動でデコードしてくれない。

いちいち日本語を encode_utf8() でくくるのはだるいので、

package Test::MyApp;
use strict;
use warnings;
use Test::More;

BEGIN {
    my $builder = Test::More->builder;
    binmode($builder->output, ':utf8');
    binmode($builder->failure_output, ':utf8');
    binmode($$builder->todo_output, ':utf8');
}

のようなクラスを作って、テストファイルで継承すればよい。

モダンPerl入門 (CodeZine BOOKS)

モダンPerl入門 (CodeZine BOOKS)