memcachedを使ったテストの書き方
DBと同様にmemcachedもテストのたびに立ち上げて,
memcachedをテストごとに立ち上げるためにはProc::GuardとTest::TCPを使用します。リスト6のようにmemcachedを立ち上げるモジュールを書いておくと便利でしょう。これを使うと,
リスト6 テ スト用のmemcachedを立ち上げるモジュール
package Test::MyApp::Memcached;
use Proc::Guard qw/proc_gurad/;
use Test::TCP qw/empty_port/;
use File::Which qw/which/;
sub start_memd {
my $port = empty_port();
my $proc = proc_guard(
scalar(which 'memcached'), '-p', $port);
wait_port($port);
return $proc, $port;
}
このようにテストごとに新しいmemcachedを立ち上げることで,
make testを高速化!
テストが増えると,
MySQLをあらかじめ立ち上げておく
Test::mysqldを使ったテストの場合,
- 1つずつテストを走らせるときは通常どおりMySQLを立ち上げる
- make testでまとめて実行する場合は,
はじめの処理でMySQLを立ち上げておいて, すべてのテストが終わったら終了する
というようにしています。まず,
リスト7 Test::MyApp::Fixture::DBIの修正
package Test::MyApp::Fixture::DBI;
use JSON;
use DBI;
use Test::mysql;
our $SKIP_DROP_DB_MAP = {
information_schema => 1,
mysql => 1,
test => 1,
};
sub start_mysql {
my %config = @_;
my $mysqld;
if (my $json = $ENV{TEST_MYSQLD}) {…①
my $obj = decode_json $json;
$mysqld = bless $obj, 'Test::mysqld';…②
cleanup($mysqld);…③
}
else {
$mysqld = Test::mysqld->new(my_cnf => +{ ―┐
'skip-networking' => '', %config, | …④
}); ―――――――――┘
}
return $mysqld;
}
sub cleanup {
my ($mysqld) = @_;
my $dbh = DBI->connect($mysqld->dsn, '', '' {
AutoCommit => 1, RaiseError => 1,
});
my $rs = $dbh->selectall_hashref(
'SHOW DATABASES', 'Database');
for my $dbname (keys %$rs) {
next if $SKIP_DROP_DB_MAP->{$dbname};
$dbh->do("DROP DATABASE $dbname");
}
}
...
①の$ENV{TEST_
make testのときにMySQLを立ち上げるには,
リスト8 Module::Install::TestTargetを使用し,
use inc::Module::Install;
use Module::Install::TestTarget;
...
default_test_target(
includes => ['t/lib'],
run_on_prepare => ['t/script/setup_mysqld.pl'],
);
...
リスト9 MySQLを起動し,
use Test::MyApp::Fixture::DBI;
use JSON;
$SIG{INT} = sub { CORE::exit 1 };
$mysqld = setup_mysqld();
$ENV{TEST_MYSQLD} = encode_json +{ %$mysqld };
これで,
できるだけテストを並列で実行する
DBのテストは速くなりましたが,j数字
という文字列を入れると,j4
とすれば4つのテストが並列に実行されるので,
この設定を有効にするには,
リスト10 make testでテストを並列実行させる
use inc::Module::Install;
use Module::Install::TestTarget;
...
default_test_target(
includes => ['t/lib'],
run_on_prepare => ['t/script/setup_mysqld.pl'],
env => { HARNESS_OPTIONS => 'j4' }, ←追加
);
...
しかし,
そこで,
package Test::MyApp::Fixture::DBI;
use Test::Synchronized;
...
Test::Synchronizedはuseするだけでそのテストが並列実行されなくなりますので,
このようにすると,
また,
- 注14) 単に
j
とするとj9
と同じになります。
おわりに
Mobage APIの実装を例に,
実際にはWeb APIを提供するうえで,
次回の執筆者は日ごろから筆者の隣に座って仕事をしている小林篤