LoginSignup
8
7

More than 5 years have passed since last update.

Test::MockObject::Extendsで手作りオブジェクトスパイ

Posted at

単体テストなどで「あるオブジェクトの特定のメソッドが呼ばれたかどうか」を検証したい時はスパイ(Spy)を使うといい。Test::MockObject::Extendsを使うと、以下のようにしてスパイを実現できる。

spy.t
package Sample;  ######## Test target object
use strict;
use warnings;

sub new {
    my ($class) = @_;
    return bless {}, $class;
}

sub foo {
    return "bar";
}

package main;    ######## Test code
use strict;
use warnings;
use Test::More;
use Test::MockObject::Extends;

my $sample = Sample->new;
my @foo_log = ();

Test::MockObject::Extends->new($sample);
my $original = $sample->can("foo");
$sample->mock(foo => sub {
    push(@foo_log, [@_]);
    goto $original;
});

is($sample->foo,             "bar", "1st foo");
is($sample->foo(2),          "bar", "2nd foo");
is($sample->foo(3, "three"), "bar", "3rd foo");

is_deeply(\@foo_log, [ [$sample], [$sample, 2], [$sample, 3, "three"] ], "log OK");

done_testing;

ポイントは、

my $original = $sample->can("foo");

を、モックメソッドの定義前に呼び出してオリジナルメソッドのcoderefを取得しておく点。モックメソッド内でgoto $originalとすれば何事もなかったかのようにオリジナルメソッドを実行できる。

別の方法?

  • Test::MockModuleでもほぼ同じ方法が使える。こちらはTest::MockModuleオブジェクトからオリジナルメソッドを取得できる。
  • もうちょっと高級な方法が好みならTest::Mock::RecorderTest::Doubleがよさそう。
  • メソッドではなく単純なcoderefのスパイならSub::Spyというモジュールが使えそう。
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7