简体   繁体   English

在perl中存根并模拟subrotine以进行单元测试

[英]stub and mock a subrotine for unit testing in perl

I am trying to do unit testing of the module. 我正在尝试对该模块进行单元测试。 I need help and information , how to mock or stub a subroutine to test package. 我需要帮助和信息,如何模拟或添加子例程来测试程序包。

I do not wish to use the module I came across on cpan. 我不想使用在cpan上遇到的模块

You an mock subs by overriding them in the following way in your test: 通过在测试中按以下方式覆盖它们,可以创建模拟子:

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

You typically want to set a variable to be checked later in your test inside your mock. 您通常希望设置一个变量,以便稍后在模拟中的测试中进行检查。

(even if I suggest using Test::MockModule, but you explicitly specified to not use it) (即使我建议使用Test :: MockModule,但您明确指定不使用它)

It's hard to tell what conditions you might have to work around, because you don't give much detail. 很难说出您可能需要解决的条件,因为您没有提供太多细节。 So this is a general overview of what's involved in mocking subroutines. 因此,这是模拟子例程中涉及的内容的一般概述。

Perl stores package subroutines in the symbol table which we can access through "globs" . Perl将包子例程存储在符号表中,我们可以通过“ globs”访问它们。 Take the subroutine do_the_thing in package Some::Package , the last subroutine you assign to the symbol *Some::Package::do_the_thing will replace the normal functionality of that sub. 将程序包Some::Package的子例程do_the_thing分配给符号 *Some::Package::do_the_thing的最后一个子程序,它将替换该子程序的常规功能。 We can also retrieve it so we can have it to call. 我们也可以检索它,以便调用它。

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

Note that to access it, we have to tell it to access the CODE slot of the glob. 请注意,要访问它,我们必须告诉它访问glob的CODE插槽。 To replace the sub, we don't. 要替换潜水艇,我们不需要。 Perl knows to assign code refs to the CODE slot of the glob. 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
    ...
};

NOTE: The way shown demonstrates a minimal way to call a procedure so it acts just like the procedure you're mocking. 注意:所示方式演示了一种最小的方法调用过程,因此它的行为就像您要模拟的过程一样 If you don't like goto , then this does the same thing: 如果您不喜欢goto ,那么它会做同样的事情:

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

However, if you want to test what was returned, or store it to set up future tests, you could simply do it like this: 但是,如果要测试返回的内容,或存储它以设置将来的测试,则可以像这样简单地进行操作:

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];
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM