Perlのテストを作っているとき、あるメソッドで呼ばれている関数が邪魔なので、任意の値を返すようなモックにしたい場合。
邪魔な関数 = 例えば、その関数はネットワークアクスが必要とか、DBアクセスして、特定のデータセットが必要とか。
テスト対象モジュール
package TestTargetXXX;
use Some::Module qw(getIDfromDB);
sub sample_func {
my $self = shift;
my %param = @_;
my $id = &getIDfromDB($param{key});
# (略)
return $key_code;
}
テストスクリプト(の一部)
subtest "sample_func test." => sub {
my $obj = TestTargetXXX->new();
%param = (key => 'XXX');
$rtn = $obj->sampel_func(\%param);
is $rtn, 'YYY';
};
ここで&getIDfromDB()
を動かすには、DBの準備が必要で面倒。なので、モック化する。(もちろん、この関数は別途、テスト済み)
テストスクリプト(新)
subtest "sample_func test." => sub {
my $test_id = undef;
no warnings 'redefine';
local *TestTarget::getIDfromDB = sub {return $test_id};
use warnings 'redefine';
my $obj = TestTargetXXX->new();
%param = (key => 'XXX');
$test_id = 'ZZZ';
$rtn = $obj->sampel_func(\%param);
is $rtn, 'YYY';
};
要点として、
-
*TestTarget::getIDfromDB = sub {...}
で強制的に関数を置き換え - 置き換えが全体に影響しないようlocalで宣言
- この置き換え方法は、警告が出るので
no wanings 'redefine';
で抑制(use warnings;使ってないなら不要)
もう少し「強制的な置き換え」について説明すると、
- getIDfromDB()は、TestTargetモジュール内でexportされている。
- そのため、getIDfromDB()はSome::Moduleのものだが、TestTargetの関数ともいえる。
- つまり、
&TestTarget::getIDfromDB()
ともいえる。 - なので、
*TestTarget::getIDfromDB = sub {}
で強制的に上書き出来る。
最後に
CPANにありそうですが、Perl単体でなら上記の方法で対処可能。あと、モックの使いすぎ注意。別途、結合テストはきちんとする。そもそも、こんなテストしにくい実装はしない。