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

时间:2011-09-09 19:44:01

标签: perl unit-testing mocking

我正在开发一个应用程序,必须逐个替换现有的意大利面条代码。为了实现这一点,我有一个调度程序,在匹配URI时运行所需的HTTP资源,否则使用旧的HTTP资源类。

因此,这个旧的HTTP资源必须require旧系统的入口点文件,我正在试图弄清楚如何测试这个过程。我现在看到它的方式是我想用mock子例程替换原始require函数,并检查它是否已使用适当的文件名调用。

这是否可能,如果没有,也许有更好的方法可以做到这一点?

3 个答案:

答案 0 :(得分:13)

要在单个包中覆盖require

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

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

全局覆盖require

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

然后:

require xyz;           # mock require: xyz.pm

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

答案 1 :(得分:10)

全局覆盖require的更好方法可能是在@INC中安装一个钩子。这个鲜为人知的功能在the require documentation的末尾描述。

这是一个简单的示例,它拦截对名称以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

答案 2 :(得分:2)

您需要注意的其他一些事项。这可以补充或替换覆盖require

的需要

您是否知道可以将代码引用添加到@INC路径中?然后,这些内容将全局应用于userequire语句。

引用perldoc require

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

有三种形式的钩子:子程序引用,数组引用和祝福对象。

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

1。文件句柄,将从中读取文件。

2。对子程序的引用。如果没有文件句柄(前一项),那么这个子程序应该每次调用生成一行源代码,将行写入$ _并返回1,最后在文件末尾返回0.如果有文件句柄,然后调用子程序作为一个简单的源过滤器,该行在$ _中读取。同样,为每个有效行返回1,并在返回所有行后返回0。

3.子程序的可选状态。州以$ _ [1]的形式传递。子例程本身的引用作为$ _ [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及更高版本。