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.
精彩评论