评估子例程的 success/failure

Evaluating the success/failure of a subroutine

关于 subs return 的价值,我有些不太清楚。 我喜欢逐个子测试我的模块,并检查它们是否发出正确的 return 值或正确的异常(如果出现这种情况)。

例如,假设我有以下代码(X::Argument::BadFormat 是从 Exception::Class 派生的异常处理程序):

    package My::Module;

    use strict;
    use warnings;

    sub new{#does things unrelated to the current question}

    sub my_sub {
        my ($self,$possible_value) = @_;

        if ($possible_value =~ q{\w}) { #Affect value to current object
            $self->{field} = $possible_value;
        }else{ #throw an exception
            X::Argument::BadFormat->throw(
                arg             => 'possible_value',
                expected_format => 'something that looks like a word',
                received_value  => $possible_value,
            );
        }
    }

在测试文件中,我将运行测试如:

my $object = My::Module->new();
throws_ok(sub {$object->my_sub('*')}, 'X::Argument::BadFormat', 'Faulty value will raise an exception');
ok($object->my_sub('turlututu'));

在以下情况下很容易测试:

但是,当我只是在当前对象中设置一个字段的值时,我没有理由return任何东西。

在那种情况下:

不需要 return 值的子程序应以

结尾
return;

在您的情况下,如果没有它,您将return获取 $possible_value 的值,这是最后执行的操作。这对 return.

来说似乎没什么用

假设您添加显式 return:

您的 throws_ok 测试看起来不错。然后您应该测试该字段是否已正确设置。不需要您的 ok 测试,因为您的潜艇不会 returning 任何东西。

在这种情况下,我只是检查以确保对象的属性设置正确。这就是这个特殊潜艇所做的一切。如果设置正常,则子正确结束。如果未设置,则在子结束之前出现问题。

my $p='blah'; 
$obj->my_sub($p); 

is $obj->{field}, $p, "my_sub() set the field attr ok";

如果 field 属性有一个 getter 就更好了,这样你就不会破坏封装,但我离题了。

Perl return默认为最后执行代码的结果。

例如:

print main();

sub main {
    my $var = 9 * 7;
}

print 将输出 63。如果您的代码可能会受到给定子例程输出的影响,那么您需要设置一个 return 值(通常认为最好的做法是始终设置subroutine/method).

末尾的显式 return
print main();

sub main {
    my $var = 9 * 7;
    return;
}

print 不会输出任何内容。

就个人而言,我总是尝试设置一个 return 值,具体取决于子例程 return 的上下文,但是如果您正在编写其他人将使用的代码,那么通常最安全的做法是 return;.

来自 Perl::Critic (link to the specific policy) 的补充说明:

Subroutine "main" does not end with "return" at line 8, near 'sub main {'.

Subroutines::RequireFinalReturn (Severity: 4)

Require all subroutines to terminate explicitly with one of the following: return',carp', croak',die', exec',exit', goto', or throw'.

Subroutines without explicit return statements at their ends can be confusing. It can be challenging to deduce what the return value will be.

Furthermore, if the programmer did not mean for there to be a significant return value, and omits a return statement, some of the subroutine's inner data can leak to the outside. Consider this case:

   package Password;
    # every time the user guesses the password wrong, its value
    # is rotated by one character
    my $password;
    sub set_password {
        $password = shift;
    }
    sub check_password {
        my $guess = shift;
        if ($guess eq $password) {
            unlock_secrets();
        } else {
            $password = (substr $password, 1).(substr $password, 0, 1);
        }
    }
    1;

In this case, the last statement in check_password() is the assignment. The result of that assignment is the implicit return value, so a wrong guess returns the right password! Adding a `return;' at the end of that subroutine solves the problem.

The only exception allowed is an empty subroutine.

Be careful when fixing problems identified by this Policy; don't blindly put a `return;' statement at the end of every subroutine.