How can I catch the output from a carp in Perl?

2020-07-03 04:25发布

I am writing a Perl module, and I am using carp to throw a non-fatal warning back to the calling program.

The carp warning works fine - I am checking if an input parameter meets a certain condition - if it does not meet the condition, a warning is sent with carp and the module continues on using a default for the parameter instead of the one the calling program passed. The warning is just to notify that a default parameter is being used instead of the passed in parameter.

My problem is with my test script. My test script is sending in a bad parameter to the module, and I am trying to catch the warning message that comes back and make sure I got the correct warning message.

My module looks something like this:

else {
  carp "value must be numeric - using default value";
}

and my test script looks like this:

eval {
  #call to my module
};
like (
    $@,
    qr/value must be numeric/,
    "Should abort on non-numeric value"
);

When I run the test, I can see the warning (it must be going to STDERR) on the screen, but the contents of the $@ variable is '' - blank.

Here is the output from my test script:

t/04bad_method_calls....ok 10/12value must be numeric - using default value at ...
#   Failed test 'Should abort on non-numeric value'
#   at t/04bad_method_calls.t line 98.
t/04bad_method_calls....NOK 12
#                   '' doesn't match '(?-xism:value must be numeric)'
# Looks like you failed 1 test of 12.

If I change the carp to a croak, my test script works - it catches the error message (but I only want to warn, not abort).

To be honest, I don't have the best understanding of eval - maybe that is not the best way to catch the warning output from carp. I tried using $SIG{WARN}, but that was empty as well.

Is there any way to capture the output from carp? It's not the biggest deal since this is just in my test script, but I'd still like to get my test script to work properly.

Thanks in advance!

3条回答
贪生不怕死
2楼-- · 2020-07-03 04:46

Another way how to catch warnings and also all STERR output:

my $stderr = '';
{
    local *STDERR;
    open STDERR, '>', \$stderr;
    do_stuf_here();
}
like( $stderr, qr/my result/, 'test stderr output' );

One can make fancy test function:

sub stderr_test (&$$) {
    my ( $code, $pattern, $text ) = @_;
    my $result = '';
    {
        local *STDERR;
        open STDERR, '>', \$result;
        $code->();
    }
    if ( UNIVERSAL::isa( $pattern, 'Regexp' ) ) {
        like( $result, $pattern, $text );
    }
    else {
        is( $result, $pattern, $text );
    }
}

# usage
stderr_test {do_stuf_here} qr/my expected STDERR output/,
    'stderr is like';
stderr_test {do_stuf_here} 'my expected STDERR output',
    'stderr is exactly';
查看更多
女痞
3楼-- · 2020-07-03 04:54

From this page, http://perldoc.perl.org/perlvar.html, it looks like you want to set the local $SIG{__WARN__} to a subroutine that will turn warnings into fatal errors for your test script. The example they give is:

local $SIG{__WARN__} = sub { die $_[0] };
eval $proggie;
查看更多
▲ chillily
4楼-- · 2020-07-03 05:01

If you're doing this from a test script, you can use of the Test::* modules that capture output for you. I tend to like Test::Output.

查看更多
登录 后发表回答