$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

Harrietを使ってprove単位でmysqldを作ってみた話

tokuhirom blog を見て、これ便利だなーと思ったので、試しにこれを使ってprove単位でTest::mysqldを起動するやつを作ってみた。

harriet用設定を作る

まずt/harriet/mysqld.plみたいなのを作る。この中でmysqldの起動とschema流し込みまでしてしまう。複数のdsnを保存しておきたければ、jsonで入れておくと良さそう。

# t/harriet/mysqld.pl
use JSON::XS;
use Path::Class;

$ENV{TEST_EPIC_DSNS} ||= do {
    require Test::mysqld;
    my $mysqld = Test::mysqld->new(
        my_cnf => {
            'skip-networking'        => '', # no TCP socket
            'default-storage-engine' => 'innodb',
        }
    ) or die $Test::mysqld::errstr;
    $HARRIET_GUARDS::MYSQLD = $mysqld;

    # schema流し込み
    my $socket = $mysqld->my_cnf->{socket};
    system "mysqladmin -uroot -S $socket create sample_test";
    system "mysql -uroot -S $socket sample_test < db/schema.sql";
    system "mysqladmin -uroot -S $socket create user_test";
    system "mysql -uroot -S $socket user_test < db/user.sql";

    my $dsns = {};
    $dsns->{sample} = $mysqld->dsn(dbname => 'sample_test');
    $dsns->{user}   = $mysqld->dsn(dbname => 'user_test');

    encode_json($dsns);
};

以下の点に注意した。

  • Test::mysqldはmy.cnfを読み込まないので、適当に設定する
  • schema流しこみはDBIでやると色々面倒なので、socket経由でコマンドで入れてしまう
  • dsnはjson環境変数

テストでharrietで設定したdsnを読み込む

さらにテスト側ではこの環境変数からdsnを読み込むようにします。

# t/sample.t
use DBI;
use JSON::XS;
my $dsns = eval { decode_json($ENV{TEST_EPIC_DSNS}) } || {};
my $dbh  = DBI->connect($dsns->{sample});

# Some tests...

あとはproveのPluginでharrietを呼び出すだけ。簡単ですね。

$ prove -PHarriet=t/harriet/ t/sample.t

まとめ

今回の設定をしておけば、テストを並列に走らせてもプロセスごとにmysqldが立っているのでDB周りでコンフリクトすることがなくなって便利ですね。あとはjenkinsなどで並列に動かせばそれなりに速く動いてくれそうです。
こういうの面倒だなーと思っていたけどHarriet使ったら一瞬でできたので便利ですね。