Reputation: 329
When writing small to medium size perl programs I have functions that I would like to test with "Test::More".
The idea is to be able to call my program like "./supertool.pl --test" to do the tests. While beeing able to use "./supertool.pl" for normal program usage.
But when I add "use Test::More qw(no_plan);" in the head section it garbles the program output and its exit code.
Here's an example which can be called in console like: './supertool.pl ; echo $? ; echo "Expected: 0"'.
#!/usr/bin/perl
use strict;
use warnings;
use Test::More qw(no_plan);
if (0)
{
note("one test");
test__x();
done_testing;
}
exit(0);
sub test_x
{
ok( 1, "1 is ok" );
}
The output is:
1..0
255
Expected: 0
But I whished the output to be
0
Expected: 0
Is it possible to tweak Test::More into not printing "1..0" and into not garbling the programs exit code when doing no tests?
Upvotes: 3
Views: 406
Reputation: 66899
There are several ways to get the behavior you want.
One way is to tell it that you won't run tests, per that command-line option
use warnings;
use strict;
use feature 'say';
use Test::More;
my $run_tests = shift;
if ($run_tests) {
Test::More->builder->no_plan;
}
else {
Test::More->builder->output('/dev/null');
Test::More->builder->skip_all('Not testing');
}
#...
if ($run_tests) {
note("one test");
test_x();
}
sub test_x { ok( 1, "1 is ok" ) }
The message for skipping won't be seen as the output is redirected to /dev/null
, as desired, but is provided as an example (and there must be something there).
I use methods from the backend Test::Builder module (Test::More->builder
returns its object) to set a plan/skip, even as there is a plan
function in Test::More
itself.
This is for consistency, since for output
we do need Test::Builder
, and as further examples of Test::Builder
, where one can find many more tools in cases where that may be needed. The Test::More
is built upon this moduel and I suggest a good perusal of it.
An alternative to declaring no_plan
is to use done_testing
at the very end of the program, conditioned on $run_tests
(but not in END
block, see docs).
Another way is to place all tests in SKIP
blocks, used for conditional testing
use warnings;
use strict;
use feature 'say';
use Test::More qw(no_plan);
my $run_tests = shift;
SKIP: {
skip_test() if not $run_test;
note("one test");
test_x();
}
sub test_x { ok( 1, "1 is ok" ) }
sub skip_test {
Test::More->builder->output('/dev/null');
skip "Not testing";
}
where output is again sent to /dev/null
, as desired in the question.
We can also use Test::Builder
methods directly, either skip
use warnings;
use strict;
use feature 'say';
use Test::More qw(no_plan);
my $run_tests = shift;
if ($run_tests) {
note("one test");
test_x();
}
else { skip_test() }
sub test_x { ok( 1, "1 is ok" ) }
sub skip_test {
Test::More->builder->output('/dev/null');
Test::More->builder->skip;
}
or perhaps reset
, for different circumstances or context
use warnings;
use strict;
use feature 'say';
use Test::More qw(no_plan);
my $run_tests = shift;
if ($run_tests) {
note("one test");
test_x();
}
else { Test::More->builder->reset }
# At the very end of the program (not in END block though)
done_testing if $run_tests;
sub test_x { ok( 1, "1 is ok" ) }
where we're now best off using done_testing
in the end.
All of these print nothing and have exit code 0
when the program is invoked without any arguments, or run tests and print messages when invoked with a "true" argument.† All of them were tested with more (than 1) testing blocks, omitted here for brevity.
The need to deal with some details above comes up because the testing framework is intended to be used in dedicated programs, not for testing pieces in a running program. And while it is possible to use it this way as well some things get more complicated.
See Test2, or perhaps its suite Test2::Suite, for a newer alternative.
† That is, "true" for Perl when passed to the program, so not 0
or empty string "''"
Upvotes: 3