我需要模拟像unlink
和rename
这样的内置运算符作为测试套件的一部分。我无法使用Test::MockObject
>> my $mock = Test::MockObject->new();
>> $mock->mock('unlink', sub { print "Mocked!\n"; });
>> unlink "foo";
0
是否可以模拟这样的内置函数?
答案 0 :(得分:5)
要使用您自己的版本覆盖Perl内置例程,您需要在编译时导入它。使用subs编译指示可以方便地实现这一点。这只会影响您导入所述子程序的包:
use subs 'chdir'; sub chdir { ... } chdir $somewhere;
要覆盖全局内置(即在所有名称空间中),您需要在编译时将函数导入
CORE::GLOBAL
伪名称空间:BEGIN { *CORE::GLOBAL::hex = sub { # ... your code here }; }
只要在没有合格包的情况下调用内置函数,就会调用新例程:
print hex("0x50"),"\n"; # prints 1
在这两种情况下,如果您想要访问原始的未更改的例程,请使用
CORE::
前缀:print CORE::hex("0x50"),"\n"; # prints 80
另见the relevant section in perldoc perlsub
:
当您覆盖内置函数时,您的替换应该与内置本机语法保持一致(如果可能)。您可以通过使用合适的原型来实现此目的。要获得可覆盖内置的原型,请使用带有参数"
CORE::builtin_name
"的原型函数。 (见prototype
)。但请注意,某些内置函数的语法不能由原型(例如system或chomp)表示。如果你覆盖它们,你将无法完全模仿它们的原始语法。
内置插件
do
,require
和glob can
也会被覆盖,但由于特殊魔法,原始语法会被保留,您无需定义替换原型。 (但你不能覆盖do BLOCK
语法。
require
还有一些额外的黑暗魔法:如果您将require
替换为require Foo::Bar
,它实际上会在"Foo/Bar.pm"
中收到@_
参数。请参阅require
。而且,正如您在上一个示例中所注意到的,如果覆盖
glob
,则<*>
glob运算符也会被覆盖。以类似的方式,覆盖
readline
函数也会覆盖等效的I / O运算符<FILEHANDLE>
。此外,覆盖readpipe
也会覆盖运算符``和qx//
。最后,某些内置插件(例如
exists
或grep
)无法覆盖。