tsucchi’s diary(元はてなダイアリー)

はてなダイアリー(d.hatena.ne.jp/tsucchi1022)から移行したものです

DBD::Mock の execute() 時のエラーを偽装する

DBD::Mock は

$dbh->{mock_add_resultset} = {
      sql => 'BEGIN SOME_PROC(); END;',
      results => DBD::Mock->NULL_RESULTSET,
      failure => [ 12345, 'なんかエラー' ],
};

こんな感じで、エラーコードを返すような仕込みができるらしいのだけど、RaiseError => 0 が指定されていると、期待通りにならない。*1execute() の戻り値を 0 にして、エラーコードを入れてほしいのだけど、例外を投げられてしまう。(RaiseError => 1 のときと同じ振る舞いをされてしまう)*2

しょうがないので、別の Mock を仕込んでエラーコードを入れるところとかを偽装する。なんかすげーバッドノウハウだな。。。

use Test::More;
use DBI;
use Test::Mock::Guard qw(mock_guard);
use utf8;
use strict;
use warnnings;

subtest 'other error', sub {
    my $error_code = '12345';
    my $error_message = 'なんかエラー';
    my $guard_dbh = mock_guard( 'DBI::db', +{
        err     => sub { $error_code },
        errstr  => sub { $error_message },
    });
    my $guard_sth = mock_guard( 'DBI::st', +{
        execute => sub { 0 },
    });
    my $mock_dbh = DBI->connect('dbi:Mock:', '', '', +{ AutoCommit => 0, RaiseError => 0 });
    $mock_dbh->{mock_add_resultset} = { # execute は偽装してるからこれはなくてもいい
        sql     => 'BEGIN SOME_PROC(); END;',
        results => [],
    };

    do_something_using_mock_dbh($mock_dbh);
    # ...
};
# ...

こうなると、「DBD::Mock いらないじゃん」とも思うのだけど、他のテストでは Mock はさんでるのに、エラー返すときだけ普通の DBI (DBD::mysql)つかうのもそれはそれで気持ち悪いし。。。どうすればいいんですかね??

*1:そもそもこの failure を指定する機能も「EXPERIMENTAL FUNCTIONALITY」とか書いてあるので、どの程度ちゃんと動くのかは分からない

*2:RaiseError=>1 しときゃいいのかもしれないけど、今のシステムが 0 を前提に組まれてるので今更変えられないし...