如何设置Perl匿名函数原型?解决Mock框架原型不匹配问题
嘿,这个原型不匹配的问题我刚好碰到过,给你分享下解决办法!
问题根源
你遇到的警告“Prototype mismatch: sub ($;$) vs none”,本质是因为原函数FunctionWithPrototype带有($;$)的原型(表示第一个参数必填,第二个可选),但你用来替换的匿名子例程默认没有原型,Sub::Override在替换时检测到原型不一致,就抛出了警告。
解决方案:给匿名子例程设置原型
Perl提供了两种给匿名sub添加原型的方式,都能解决这个问题:
方式1:定义匿名sub时直接指定原型
在写匿名sub的时候,直接在sub后面加上和原函数一致的原型,比如:
# 和原函数原型($;$)保持一致 my $mock_sub = sub ($;$) { my ($arg1, $arg2) = @_; # 这里写你的mock逻辑,比如返回固定值或者自定义处理 return "Mocked result: $arg1" . ($arg2 ? " | $arg2" : ''); };
方式2:动态给已存在的匿名sub设置原型
如果已经创建了匿名sub,后期可以用prototype函数为它设置原型:
my $mock_sub = sub { my ($arg1, $arg2) = @_; return "Dynamic mock: $arg1" . ($arg2 ? " + $arg2" : ''); }; # 关键:设置和原函数相同的原型 prototype($mock_sub) = '($;$)';
结合Test::Mockify和Sub::Override的完整示例
先看你的Hello包示例:
package Hello; sub FunctionWithPrototype ($;$) { my ($arg1, $arg2) = @_; return "Original: $arg1" . ($arg2 ? " and $arg2" : ''); } 1;
然后在测试脚本里这样用:
use Test::More; use Test::Mockify; use Sub::Override; use Hello; # 用方式1替换函数 my $override = Sub::Override->new( 'Hello::FunctionWithPrototype' => sub ($;$) { my ($arg1, $arg2) = @_; return "Mocked: $arg1" . ($arg2 ? " | $arg2" : ''); } ); is(Hello::FunctionWithPrototype('foo'), 'Mocked: foo', 'Mock without second argument works'); is(Hello::FunctionWithPrototype('foo', 'bar'), 'Mocked: foo | bar', 'Mock with second argument works'); $override->restore; # 用方式2替换函数 my $dynamic_mock = sub { my ($arg1, $arg2) = @_; return "Dynamic Mock: $arg1" . ($arg2 ? " + $arg2" : ''); }; prototype($dynamic_mock) = '($;$)'; my $override2 = Sub::Override->new( 'Hello::FunctionWithPrototype' => $dynamic_mock ); is(Hello::FunctionWithPrototype('baz'), 'Dynamic Mock: baz', 'Dynamic mock without second argument works'); is(Hello::FunctionWithPrototype('baz', 'qux'), 'Dynamic Mock: baz + qux', 'Dynamic mock with second argument works'); # 也可以直接用Test::Mockify的mock方法 my $Mockify = Test::Mockify->new('Hello'); $Mockify->mock('FunctionWithPrototype', sub ($;$) { return "Mockify result: " . join(', ', @_); }); is(Hello::FunctionWithPrototype('test'), 'Mockify result: test', 'Test::Mockify works with prototype'); done_testing();
这样处理后,不仅原型不匹配的警告会消失,mock的函数还能保持原函数的参数调用规则(比如第一个参数必填,第二个可选),和原函数的行为一致。
内容的提问来源于stack exchange,提问作者Christian Breitkreutz
相关产品推荐
相关产品推荐

