$shibayu36->blog;

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

DBIx::QueryLogを使ってちゃんとSQLが流れているかテストする

 DBIのconnectのCallbacksなどでSQLを実行している時とかに、実際にSQLが流れているのかチェックしたい時がある。そういう時どうするのがベスト・プラクティスなのかわからないのだけど、DBIx::QueryLogを使ったら一応できたのでメモ。

テストしたい状況

package My::DBI;
use strict;
use warnings;

use DBI;

sub connect {
    my ($dsn, $username, $password) = @_;
    my $dbh = DBI->connect($dsn, $username, $password, {
        Callbacks => {
            connected => sub {
                my $dbh = shift;
                $dbh->do("SET NAMES utf8") or warn $dbh->errstr;
                return;
            }
        }
    });
}

1;

これのSET NAMES utf8がconnectした時にちゃんと流れているかテストしたい。実際はもうちょっと複雑なときにテストしたい。

DBIx::QueryLogを使ってテストする

DBIx::QueryLogにはloggerを設定できる機能があるので、これを使って文字列にSQLを格納しておくことでテストする。

まず、Logger。

package My::SQL::Logger;
use strict;
use warnings;

sub new {
    my $class = shift;
    return bless {
        sqls => '',
    }, $class;
}

sub log {
    my ($self, %args) = @_;
    $self->{sqls} .= $args{params}->{sql};
}

1;

これを使ってDBIx::QueryLogでログを取って、テストする。

use strict;
use warnings;

use Test::More;

use DBIx::QueryLog ();

my $logger = My::SQL::Logger->new;
DBIx::QueryLog->logger($logger);

my $guard = DBIx::QueryLog->guard;
My::DBI->connect('dbi:mysql:dbname=sample;host=localhost', 'user', 'pass');

like $logger->{sqls}, qr{SET NAMES utf8};

その他のやり方

 とりあえず強引にやった感じだけど、もしかしたら他にやり方があるかもしれない。今回の例だったらDBIのdoメソッド置き換えればいいだけみたいな感じだったけど、DBIの中身結構複雑でどれを置き換えたらいいかよく分からなかった。あと流れてるSQL知りたいだけなら、DBIの標準機能であるのかもしれない。
 何か良い方法があれば教えてください。