スタブでオリジナルのメソッドを呼び出す
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
うーん。いけたけどこれしかないのかな(。-`ω´-)ウーム