开发者

How do you "catch" a pod2usage exit in a Perl Script with Try::Tiny?

I'm currently trying to learn unit testing. To do this I'm writting a script at work, and I'm creating unit tests for the entire script. Thus far thi开发者_运维技巧ngs have been going well, but I'm trying to test that incorrect data entered into the script form the command line triggers a help message.

My code looks something like:

sub getContext{
   my ($help) = @_;

GetOptions(
  help|h => \$help,
   ...

pod2usage if $help;
... 
}

My tests look something like:

my $help_exception = 0;
try{  
   getContext( {help => 0} );
}catch{
 $help_exception = 1; 
}

ok($help_exception, "Script died correctly when given help flag");

My output looks very similar to:

1..4

ok 1 - use scripts::scriptname;

ok 2

ok 3

# Looks like you planned 4 tests but ran 3.

# Looks like your test exited with 1 just after 3.

The test for the help flag is test 4, it looks like my script is exiting without triggering the Try::Tiny try catch block. Is there a way to fix this, or should I be writing my tests differently?


Pod::Usage's documentation for it's -exitval argument shows how to stop it from exiting all together. You could simply use that and adapt your code and/or tests accordingly.

Otherwise, exit is not an exception, and therefore not trappable like an exception. However, it is overridable through CORE::GLOBAL::exit. Using that is a reasonable approach as well, assuming your properly localise your modifications.

Alternatively, you can always just start a subprocess to run your entire script and capture what it does, basing your tests on that, entirely avoiding the problem of Pod::Usage calling exit.

On a related note, the way you're using Try::Tiny in your test is a bit odd. I believe using Test::Fatal (which is based on Try::Tiny) might make for clearer tests in the future.


The problem is that pod2usage does exit and not throwing an exception. I don't think it can be captured this way.

Why not calling whole script in test and checking return value/output matches your expectations?


As bvr answered: a program/script is not really unit testable as it's not made of reusable parts/units. You should test it holistically. Execute it with command line arguments and check its output and errors. E.g., using Capture::Tiny–

use warnings;
use strict;
use Capture::Tiny qw( capture );
use Test::More;

my $script = "/bin/ls";

plan skip_all => "Have no `$script` to check"
    unless -x $script;

my ( $out, $err ) = capture {
    system($script, "-1", "/");
};

like( $out, qr{^bin$}m, "$script finds bin" );
ok( ! $err, "...without error" );

done_testing(2);

Output from prove

/home/apv/ab ..
ok 1 - /bin/ls finds bin
ok 2 - ...without error
1..2
ok
All tests successful.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜