Unit testing and integration in perl with Test :: More - how to capture the exit call?
I have this script that converts a file from csv split into a constrained pipe (csv2pipe.pl).
The pipe delimited file is then loaded into the database.
I'm trying to run unit testing for it (csv2pipe_unit_test.pl with a test call like (main () ...).
The sub main () function in csv2pipe.pl has a call to exit if there is no given parameter.
Unfortunately, it is impossible to complete the exit call in test call so the test program just exits.
I can't do eval {code}. It doesn't catch the exit call. It will catch death and any errors, but not quit.
Same with the Capture :: Tiny package from CPAN. It doesn't catches the exit call.
Any ideas on how to test this main () call and exit call to exit?
File: csv2pipe.pl
#!/bin/perl
use strict;
use Getopt::Std;
#--------------------------
# all work done in main sub
#--------------------------
unless (caller) { main(); exit; }
sub main {
printf( "START---$0---%s---\n", scalar( localtime(time) ) );
if ( scalar(@ARGV) < 4 ) {
print "Usage: $0 -i file.csv -o file.pipe\n";
exit;
}
my %options = ();
getopts( "i:o:", \%options );
my $file_out = $options{o} or die "Missing -o param";
my $file_inp = $options{i} or die "Missing -i param";
if ( !-f $file_inp ) {
die "Could not find file to parse ($file_inp)\n";
}
my $row_ctr = 0;
open( FH_inp, "<$file_inp" ) or die "Could not open file: $file_inp";
open( FH_out, ">$file_out" ) or die "Could not open file: $file_out";
my ( $str, $ret );
foreach $str (<FH_inp>) {
$row_ctr++;
#print "str=$str";
$ret = csv2pipe($str);
#print "ret=$ret";
print FH_out $ret;
}
close(FH_inp);
close(FH_out);
print "Processed $row_ctr rows\n";
printf( "END---$0---%s---\n", scalar( localtime(time) ) );
printf( "Program Run Time: %s second(s).\n", ( time - $^T ) );
}
# convert csv to pipe
sub csv2pipe {
my $str = shift;
return undef if !defined $str;
#print ''.(caller(0))[3]."\n";
$str =~ s/,/|/g;
if ( $str =~ /"/ ) {
while ( $str =~ /".*?"/ ) {
my $beg = $`;
my $match = $&;
my $end = $';
$match =~ s/"//g;
$match =~ s/\|/,/g;
$str = $beg . $match . $end;
}
} elsif ( $str =~ /'/ ) {
while ( $str =~ /'.*?'/ ) {
my $beg = $`;
my $match = $&;
my $end = $';
$match =~ s/'//g;
$match =~ s/\|/,/g;
$str = $beg . $match . $end;
}
}
return $str;
}
File: csv2pipe_unit_test.pl
#!/bin/perl
use strict;
use warnings;
use Test::More;
# enter main test loop
run_tests();
exit;
sub run_tests {
printf( "START---$0---%s---\n", scalar( localtime(time) ) );
require_ok "csv2pipe.pl";
ok( csv2pipe('') eq '', 'test empty string' );
ok( csv2pipe('a') eq 'a', 'test one char' );
ok( csv2pipe('a,b') eq 'a|b', 'test two chars' );
ok( csv2pipe('a,b,abc,def,') eq 'a|b|abc|def|', 'test multiple strings' );
ok( csv2pipe("abc,def,abc'xyz") eq "abc|def|abc'xyz", 'test single quote in string' );
ok( csv2pipe('abc,def,abc"xyz') eq 'abc|def|abc"xyz', 'test double quote in string' );
ok( csv2pipe('abc,def,"abc,xyz"') eq 'abc|def|abc,xyz', 'test double quoted comma does not get converted' );
ok( csv2pipe("abc,def,'abc,xyz'") eq 'abc|def|abc,xyz', 'test single quoted comma does not get converted' );
# this call does not work!!!
# exit in csv2pipe.pl function main() will exit this testing script as well
like(
main(), # first param = argument to program
qr/Usage:/, # second param = expected result
'test run program with no parameter'
); # 3rd parameter = test description
print "Tests Executed: ";
done_testing();
printf( "END---$0---%s---\n", scalar( localtime(time) ) );
printf( "Program Run Time: %s second(s).\n", ( time - $^T ) );
}
Normal Test Output:
C:\workspace\csv2pipe>c:\perl\bin\perl csv2pipe_unit_testing.pl
START---csv2pipe_unit_testing.pl---Fri Sep 12 15:15:47 2014---
ok 1 - require 'csv2pipe.pl';
ok 2 - test empty string
ok 3 - test one char
ok 4 - test two chars
ok 5 - test multiple strings
ok 6 - test single quote in string
ok 7 - test double quote in string
ok 8 - test double quoted comma does not get converted
ok 9 - test single quoted comma does not get converted
Tests Executed: 1..9
END---csv2pipe_unit_testing.pl---Fri Sep 12 15:15:48 2014---
Program Run Time: 1 second(s).
Test exit on failure in sub main () exit:
C:\workspace\csv2pipe>c:\perl\bin\perl csv2pipe_unit_testing.pl
START---csv2pipe_unit_testing.pl---Fri Sep 12 15:20:49 2014---
ok 1 - require 'csv2pipe.pl';
ok 2 - test empty string
ok 3 - test one char
ok 4 - test two chars
ok 5 - test multiple strings
ok 6 - test single quote in string
ok 7 - test double quote in string
ok 8 - test double quoted comma does not get converted
ok 9 - test single quoted comma does not get converted
START---csv2pipe_unit_testing.pl---Fri Sep 12 15:20:49 2014---
Usage: csv2pipe_unit_testing.pl -i file.csv -o file.pipe
# Tests were run but no plan was declared and done_testing() was not seen.
source to share
If you can't turn exit
in die
, try it Test::Trap
. From a quick overview:
use Test::More;
use Test::Trap;
my @r = trap { some_code(@some_parameters) };
is ( $trap->exit, 1, 'Expecting &some_code to exit with 1' );
is ( $trap->stdout, '', 'Expecting no STDOUT' );
like ( $trap->stderr, qr/^Bad parameters; exiting\b/, 'Expecting warnings.' );
source to share