存根并模拟用于perl中单元测试的子程序

时间:2014-02-13 14:21:39

标签: perl mocking stub

我正在尝试对模块进行单元测试。我需要帮助和信息,如何模拟或存根子程序来测试包。

我不想使用我在cpan.

上遇到的模块

2 个答案:

答案 0 :(得分:4)

通过在测试中以下列方式覆盖它们来模拟子类:

no warnings;
local *Foo::bar = sub {
    # do stuff
};
use warnings;

您通常希望稍后在模拟中的测试中设置要检查的变量。

(即使我建议使用Test :: MockModule,但你明确指定不使用它)

答案 1 :(得分:2)

很难说出你可能需要解决的条件,因为你没有提供太多细节。因此,这是对模拟子例程所涉及内容的一般概述。

Perl在我们可以通过"globs"访问的符号表中存储包子例程。获取包do_the_thing中的子例程Some::Package,分配给符号 *Some::Package::do_the_thing的最后一个子例程将替换该子例程的正常功能。我们也可以检索它,以便我们可以调用它。

my $do_the_original_thing = *Some::Package::do_the_thing{CODE};

请注意,要访问它,我们必须告诉它访问glob的CODE插槽。要替换sub,我们不会。 Perl知道将代码引用分配给glob的CODE槽。

*Some::Package::do_the_thing = sub { 
    if ( $_[0] eq '-reallyreallydoit' and $_[1] ) { 
        shift; shift;
        goto &$do_the_original_thing; # this does not return here
    }
    # do the mock thing
    ...
};

注意:显示的方式演示了一种调用过程的最小方法,因此它就像 一样操作。如果您不喜欢goto,那么这会做同样的事情:

        #goto &$do_the_original_thing; # this does not return here
        return &$do_the_original_thing; # this returns here...to return

但是,如果您想测试返回的内容,或者将其存储以设置将来的测试,您可以这样做:

my $future_test_value ;
*Some::Package::do_the_thing = sub { 
    if ( $_[0] eq '-reallyreallydoit' and $_[1] ) { 
        shift; shift;
        my @res;
        if ( wantarray ) {
            @res = &$do_the_original_thing;
        }
        elsif ( !( wantarray // 1 )) { 
            $res[0] = &$do_the_original_thing;
        }
        $future_test_value = $res[0];
        return wantarray ? @res : $res[0];
    }