Akata Works

フルスタックなクリエイターになる・・つもりの二年目Webエンジニアのブログ

スタブでオリジナルのメソッドを呼び出す

Test::Mock::Guardモジュール便利ですよね。シンプルで使いやすいので、よくこれでメソッドの動作を変えたりしてます。

しかしこの前、かなりシビアな条件でのみ起こり得るバグに遭遇してしまい、
Forkしたりスリープ埋め込んだりして、
なんとか再現しようとしたら見事に再帰りました(¨)( :)(..)(: )ゴ-ロゴロ

#!/usr/bin/env perl

use strict;
use warnings;

use utf8;

use Test::More;
use Test::Mock::Guard 'mock_guard';

run_test() if $ENV{ HARNESS_ACTIVE };

{
  package Test;

  sub add {
    return $_[0] + $_[1];
  }
}

sub run_test {
  my $guard = mock_guard( 'Test', +{ add => sub { print "hoge\n"; sleep 1; shift->add( 1, 2 ); } } ); # オリジナルのTest->addメソッドを期待していた

  is( Test->add( 1, 2 ), 3 );

  done_testing;

  return;
}

これを実行するとこうなる。

akata:^_^[~/perl_test/mock_test]$ prove -v main.pl
main.pl ..
hoge
hoge
.
.

( ゚д゚)ポカーン

モックされたメソッドが永遠に呼び出され続けています。


仕方がないのでTest::MockModuleモジュールを使って、内部からオリジナルのメソッドを呼び出すことで解決出来ました。

sub run_test {
  my $module = Test::MockModule->new( 'Test' );
  $module->mock( 'add', sub { shift; print "hoge\n"; sleep 1; $module->original( 'add' )->( @_ ) } );

  is( Test->add( 1, 2 ), 3 );

  done_testing;

  return;
}
akata:^_^[~/perl_test/mock_test]$ prove -v main.pl
main.pl ..
hoge
ok 1
1..1
ok
All tests successful.
Files=1, Tests=1,  2 wallclock secs ( 0.02 usr  0.00 sys +  0.03 cusr  0.00 csys =  0.05 CPU)
Result: PASS

うーん。いけたけどこれしかないのかな(。-`ω´-)ウーム