最初は、テスト用のmysqldを立ち上げっぱなしにしておいて、
それを使うテストを prove -lr t で走らせたものであった。
そのテストに10分以上かかるようになると、我慢がならなくなり、
Test::mysqldを使い、
1
| |
で走らせるようになった。
それでも10分以上かかるようになると、また我慢がならなくなり、
App::Prove::Plugin::MySQLPool – github, cpan
というのを書き、
1
| |
でテストを走らせるようになった。
App::Prove::Plugin::MySQLは、Test::mysqldを使ったテストが大量にある時に、
テストの最初に -j* 分のmysqldを起動し、
それぞれの *.t にはそのmysqld群の中から使っていないものを
割り当てるproveプラグインである。
Test::mysqldを使ったテストの最初では、CREATE TABLEをしまくったり、マスターデータをINSERTしまくったりするだろう。
App::Prove::Plugin::MySQLは、-j*分のmysqldを起動すると、それぞれに対して、
1
| |
として指定したモジュールの
1
| |
関数を呼ぶ。
(指定しない場合には何もしない。)
その中で、GitDDLを使って、
# MyApp::Test::DB
sub prepare {
my ($package, $mysqld) = @_;
my $gd = GitDDL->new( dsn => $mysqld->dsn, ... );
$gd->deploy;
}
というようにしてテストの前準備をすればいい。
これが終わると、私のテストをやっと実行する。
1
| |
にdsnがやってくるので
こんなふうにして使う。
my $dbh = DBI->connect( $ENV{ PERL_TEST_MYSQLPOOL_DSN } );
$dbh->do( "TRUNCATE $_" ) for @tables;
... # your test code
同じmysqldが使い回されてくるので、中身を毎度消してやる。
実装には試行錯誤したし、いまいちなところも多い気がする。
テストコードをなるべく変更せずに(%ENVの書き換えだけで)使えるようにするには、POSIX::AtForkを使ってfork後に子プロセス内で%ENVをセットした。
他にproveプラグインでうまくフックできるのだろうか?
1つの *.t ファイルのテストの前にmysqldをpoolから確保し、
テストが終了したら、そこで使ったmysqldは開放して次のテストに割り当てたい。
get_and_setをatomicにできるCache::FastMmapを使って、
確保時にはPOSIX::AtForkで子プロセス内から自分のpidをキャッシュにセットして、
開放時には終了したテストのpidをとれなかったので、死んだプロセスがあるかどうかをpsでまわして調べるなどしている。
よくわからないだろうけれど、がんばったし、
テストはまた4分くらいで終わるようになったし、よく眠れそうだ。