0

moops を使用して便利なモック クラスを構築しようとしています。

#!/usr/bin/env perl
use Modern::Perl '2014';
use Moops;
use Test::More;

class aClass {
  method m {}
  method l {}
};

class NotWorkingMockAClass
extends aClass {

  has methodCallLog => (
    is  => 'rw',
    default => sub { [] },
    isa     => ArrayRef
  );

  around m, l {
    push $self->methodCallLog, (caller(0))[3] =~ m/::(\w+)$/;
    $next->($self, @_ );
  }

};

my $mac = NotWorkingMockAClass->new();
$mac->m();
$mac->l();
$mac->m();

is( ($mac->methodCallLog)->[0], 'm', 'mcl[0] == m' );
is( ($mac->methodCallLog)->[1], 'l', 'mcl[1] == l' );
is( ($mac->methodCallLog)->[2], 'm', 'mcl[2] == m' );

これにより、次の結果が得られます。

$ perl mocking.pl 
ok 1 - mcl[0] == m
not ok 2 - mcl[1] == l
#   Failed test 'mcl[1] == l'
#   at mocking.pl line 33.
#          got: 'm'
#     expected: 'l'
ok 3 - mcl[2] == m

したがって、問題は、ショートカットを使用するとcaller()常に返されるようです。maround m,l ..

クラスを次のように定義します。

class WorkingMockAClass
extends aClass {

  has methodCallLog => (
    is  => 'rw',
    default => sub { [] },
    isa     => ArrayRef
  );

  method _logAndDispatch( CodeRef $next, ArrayRef $args ){
    push $self->methodCallLog, (caller(1))[3] =~ m/::(\w)$/;
    $next->($self, @$args );
  }
  around m {
    $self->_logAndDispatch( $next, \@_ );
  }

  around l {
    $self->_logAndDispatch( $next, \@_ );
  }
};

動作しますが、もう少し冗長で書きにくいです。

Moops でこのようなことを達成するためのより良いオプションはありますか?

4

1 に答える 1

2

個人的には Moops であろうとなかろうcallerと、修飾子が適用される可能性のあるメソッドは信頼できません。また、それらの修飾子でそれを信頼することもありません. メソッド修飾子がどのように機能するかの内部に頼りすぎています。(Moo/Moose/Mouse で異なります。)

このようなことを試しましたか?

push @{ $self->methodCallLog }, Sub::Identify::sub_name($next);

(または、Sub::Identify の代わりに Sub::Util を使用します。)

于 2015-01-28T23:01:11.703 に答える