有没有办法在Perl中模拟内置的require函数?

有没有办法在Perl中模拟内置的require函数?,perl,unit-testing,mocking,Perl,Unit Testing,Mocking,我正在开发一个应用程序,它必须一块一块地替换现有的杂乱无章的代码。为了实现这一点,我有一个dispatcher,在URI匹配时运行所需的HTTP资源,否则使用遗留HTTP资源类 因此,这个遗留HTTP资源必须需要旧系统的入口点文件,我正试图找出如何测试这个过程。我现在看到的是,我想用一个模拟子例程替换原来的require函数,并检查是否已使用适当的文件名调用它 这可能吗?如果不可能,可能有更好的方法吗?要在单个包中覆盖require: use subs 'require'; # imports

我正在开发一个应用程序,它必须一块一块地替换现有的杂乱无章的代码。为了实现这一点,我有一个dispatcher,在URI匹配时运行所需的HTTP资源,否则使用遗留HTTP资源类

因此,这个遗留HTTP资源必须
需要旧系统的入口点文件,我正试图找出如何测试这个过程。我现在看到的是,我想用一个模拟子例程替换原来的
require
函数,并检查是否已使用适当的文件名调用它


这可能吗?如果不可能,可能有更好的方法吗?

要在单个包中覆盖
require

use subs 'require';  # imports `require` so it can be overridden

sub require {print "mock require: @_\n"}

要全局覆盖
要求

BEGIN {
    *CORE::GLOBAL::require = sub {print "mock require: @_\n"}
}
然后:

require xyz;           # mock require: xyz.pm

require Some::Module;  # mock require: Some/Module.pm

全局覆盖
require
的更好方法可能是在
@INC
中安装一个钩子。这个鲜为人知的功能将在本章末尾介绍

下面是一个简单的示例,用于拦截对名称以HTTP开头的模块的任何请求:

BEGIN {
  unshift @INC, sub {
    my ($self, $file) = @_;
    return unless $file =~ /^HTTP/;
    print "Creating mock $file\n";
    my @code = "1"; # Fake module must return true
    return sub { $_ = shift @code; defined $_ };
  }
}

require HTTP::Foo;
use HTTPBar;

请注意,这也会模拟
use
,因为它基于
require

钩子可以作为代码引用添加到
@INC
路径中。然后这些将全局应用于
use
require
语句

引用perldoc的话

还可以通过将Perl代码直接放入@INC数组,将钩子插入导入工具

钩子有三种形式:子例程引用、数组引用和对象。

子程序引用是最简单的情况。当包含系统遍历@INC并遇到子例程时,将使用两个参数调用该子例程,第一个参数是对自身的引用,第二个参数是要包含的文件的名称(例如,“Foo/Bar.pm”)。子例程应返回nothing(无),或按以下顺序返回最多三个值的列表:

一,。从中读取文件的文件句柄

二,。对子程序的引用。如果没有filehandle(上一项),则该子例程将在每次调用中生成一行源代码,将该行写入$并返回1,最后在文件末尾返回0。如果有filehandle,则将调用该子例程作为简单的源筛选器,行为在$\中读取。同样,每个有效行返回1,所有行返回后返回0

3.子程序的可选状态。该状态作为$\uU1]传入。对子例程本身的引用作为$\u0[0]传入

下面是一个例子:

#!/usr/bin/perl

sub my_inc_hook {
    my ($sub_ref, $file) = @_;

    unless ($file =~ m{^HTTP/}) {
        warn "passing through: $file\n";
        return;
    }

    warn "grokking: $file\n";
    return (\*DATA);
}

BEGIN {
    unshift(@INC, \&my_inc_hook);
}

use strict;
require warnings;
require HTTP::Bazinga;

HTTP::Bazinga::it_works();

__DATA__
package HTTP::Bazinga;

sub it_works {warn "bazinga!\n"};

1;
产生:

$ perl inc.pl
passing through: strict.pm
passing through: warnings.pm
grokking: HTTP/Bazinga.pm
bazinga!

我相信这对perl 5.10.0及更高版本是有效的。

这难道不模拟
只需要该模块的
函数吗?我需要它被嘲笑为所有其他模块以及。感谢扩展的解释,我已经接受了类似的答案,我相信这是第一次张贴。