最初は、テスト用の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分くらいで終わるようになったし、よく眠れそうだ。