Running only one named test case in a Perl test file - perl

I am trying to find if it is possible to run just one test case in a Perl test file. For example, consider the following Perl test file (copied from http://www.thegeekstuff.com/2013/02/perl-test-simple/):
#!/usr/bin/perl
use strict;
use warnings;
use Test::Simple tests => 2;
sub hello_world
{
return "Hello world!";
}
sub get_number
{
return int(rand(1000));
}
ok( hello_world( ) eq "Hello world!", "My Testcase 1" );
ok( get_number( ) > 0, "My Testcase 2" );
When I run this file using command prove -v test.t I get following output:
test.t ..
1..2
ok 1 - My Testcase 1
ok 2 - My Testcase 2
ok
Now, I just want to run the 2nd test case i.e. My Testcase2. Is there a way to execute just one named test case in a test file?

The short answer is: No, with the simple test framework provided by Test::Simple (or Test::More) and the prove command there is no way to single out one specific assertion from a test script and run just that assertion.
However the Perl testing ecosystem has a rich and diverse set of options available. For example Test::Class allows you to add an object oriented layer on top of the standard test protocol. This allows you to group tests into methods, add setup and teardown methods, and also to run individual test methods. You still won't be able to do it all from the command-line without modifying your test script but it's a step closer to what you're asking for.
Of course a much simpler solution would be to copy out just the the bit you want into its own .t file and run that.

Related

How to test missing optional perl modules via the command line perl call

I have a test suite with hundreds of tests for a perl module I've yet to release which is a command line interface. Since it is a command line interface, the tests (until possibly now) are all written to drop code into a template and then call the template script using a system call.
I recently added an optional dependency on a 3rd party module that's not a part of core perl. I know my module works whether that module is installed or not because I have a computer with it installed and one without and the module works without error in each case. However, I'd like to be able to write a test to confirm that my module will work when the 3rd party module is absent - and I'd like that test to work even if the 3rd party module is installed, but behave as if it wasn't.
Ideally, I could use the structure I've put in place for testing which makes a system call to a template script. I know I could write a separate test script that manipulates #INC in the BEGIN block, imports the particular methods that use the module, and call them like a unit test. But I would like to know if there's a way I can use the test structure I've already got all my other tests using, which is to make a system call.
So is there a way to exclude a module from being imported via a perl command line option? I've tried -M-Module, but the code use Module still imports the module.
Incidentally, my module uses the 3rd party module inside an eval, which is how I made it optional.
I wrote Test::Without::Module for this exact case. It works by modifying #INC to prevent loading of modules that you name. For testing, you could either run the test from the command line:
perl -MTest::Without::Module=Some::Module -w -Iblib/lib t/SomeModule.t
Or allow/disallow loading the module from within your test suite:
use Test::Without::Module qw( My::Module );
# Now, loading of My::Module fails :
eval { require My::Module; };
warn $# if $#;
# Now it works again
eval q{ no Test::Without::Module qw( My::Module ) };
eval { require My::Module; };
print "Found My::Module" unless $#;

How can I debug a single Perl unit test sub?

I have the usual MakeMaker module with a t/ tests directory, and I can run a single test file with e.g., prove -I lib t/my-test.t.
My tests use Test::Class and Test::More and subs (with the modulino technique from Effective Perl), like this:
use strict;
use warnings;
use base 'Test::Class';
use Test::More;
__PACKAGE__->runtests() unless caller;
sub set_up : Test(setup) {
# ...
}
sub test_something : Test {
is(MyModule::some_sub(1), 1);
}
# ...more test subs...
Now I want to use the Perl debugger to investigate a test sub that shows a problem in my module. I want to only run test_something in the debugger, without running all the other test subs in the .t file.
prove does not seem to have such an option.
perl -d -I lib t/my-test.t runs all tests, unless I change my modulino to call the setup method and then the actual test method instead of __PACKAGE__->runtests():
unless (caller) {
set_up();
test_something();
done_testing();
}
How can I run only one test sub without modifying the code?
To avoid running all of your tests, caller must be defined when your test script is loaded. Try something like this:
$ perl -Ilib -de 1
DB<1> do 't/my-test.t'
DB<2> set_up()
DB<3> b test_something_else
DB<4> test_something_else()
... step through test_something_else() function ...
DB<16> done_testing()

How to avoid "You tried to plan twice" at Test::More

I'm new with unit testing.
I'm pretending to load N classes that internally uses Test::More in target to make different tests with their own encapsulation.
But I'm receveing the error: "You tried to plan twice at Tests/Bar.pm line 9."
This method of "more than one test" it's correct one, I mean it's an standard way for doing unit tests in perl? How can I get this level of encapsulation using Test::More?
Thanks in advice!
main.pl :
use strict;
use warnings;
use utf8;
use Tests::Foo;
use Tests::Bar;
my $ret1 = Tests::Foo->run();
my $ret2 = Tests::Bar->run();
Tests::Foo :
package Tests::Foo;
use strict;
use warnings;
sub run
{
my $ret;
use Test::More qw(no_plan);
my $test = Test::More->builder;
is(1,1,'correct()');
is(1,2,'fails()');
return $test;#return all test object
}
1;
Tests::Bar
package Tests::Bar;
use strict;
use warnings;
sub run
{
my $ret;
use Test::More qw(no_plan);
my $test = Test::More->builder;
is(2,1,'fail()');
is(2,2,'correct()');
return $test;#return all test object
}
1;
The Test::More module is built around the TAP format (Test Anything Protocol). The first line of the test output can contain a line that declares the number of tests: 1..12. This is useful for tools that output the fraction of successful or failed tests: 3/12 tests failed. However, this line is optional and you can use no plan. In this case it makes sense to say when you're done_testing:
use Test::More;
is 1, "1", "stringification";
done_testing;
Note that use Test::More 'no_plan' is considered as a plan by Test::More, although it doesn't declare anything in the TAP output.
You should declare a plan (or declare that you're done) only once per process. This is not a problem, as usually testing goes like this:
In your project directory, you have the folders lib/ with your modules, and t/ with your tests. Here an example for the Foo::Bar module:
./
lib/
Foo/
Bar.pm
Bar/
Helper.pm
t/
00_first_test.t
01_second_test.t
A test looks like this:
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More tests => 1;
# some test here
BEGIN {
use_ok 'Foo::Bar';
}
That is, it preferably has a shebang and declares the number of tests. A package name is not required.
The tests are run with the prove tool which ships with Perl. Inside the directory:
$ prove -lr t/
The -l includes the lib directory, -r also looks at subfolders. You can then specify a list of tests or directories containing tests. The tests inside a directory are usually processed alphabetically, but there are options to stir that up.
This will execute a separate process for each test. This is robust, easy to implement and to parallelize, although not terribly performant. This implies that each test is responsible for creating a fixture of it's own.
It is therefore not necessary to call your tests from a central testing script or a makefile.
If you want to execute multiple tests in the same TAP session, you can use subtests:
use Test::More tests => 2;
ok some_test;
subtest "Nice Name" => sub {
plan tests => 1;
ok other_test;
};
Inside the subtest, the plan is declared with the plan function, not with use Test::More (which would be executed at compile time, before the subtest is executed)! You could structure your test objects to be executed as subtests:
package Tests::Something;
use Test::More;
sub run {
my $self = shift;
plan tests => 2;
ok some_test;
ok other_test;
}
Then:
subtest "Tests::Something" => sub {
Tests::Something->new->run;
}

How can I compile a Perl script inside a running Perl session?

I have a Perl script that takes user input and creates another script that will be run at a later date. I'm currently going through and writing tests for these scripts and one of the tests that I would like to perform is checking if the generated script compiles successfully (e.g. perl -c <script>.) Is there a way that I can have Perl perform a compile on the generated script without having to spawn another Perl process? I've tried searching for answers, but searches just turn up information about compiling Perl scripts into executable programs.
Compiling a script has a lot of side-effects. It results in subs being defined. It results in modules being executed. etc. If you simply want to test whether something compiles, you want a separate interpreter. It's the only way to be sure that one testing one script doesn't cause later tests to give false positives or false negatives.
To execute dynamically generated code, use eval function:
my $script = join /\n/, <main::DATA>;
eval($script); # 3
__DATA__
my $a = 1;
my $b = 2;
print $a+$b, "\n";
However if you want to just compile or check syntax, then you will not be able to do it within same Perl session.
Function syntax_ok from library Test::Strict run a syntax check by running perl -c with an external perl interpreter, so I assume there is no internal way.
Only work-around that may work for you would be:
my $script = join /\n/, <main::DATA>;
eval('return;' . $script);
warn $# if $#; # syntax error at (eval 1) line 3, near "1
# my "
__DATA__
my $a = 1
my $b = 2;
print $a+$b, "\n";
In this case, you will be able to check for compilation error(s) using $#, however because the first line of the code is return;, it will not execute.
Note: Thanks to user mob for helpfull chat and code correction.
Won't something like this work for you ?
open(FILE,"perl -c generated_script.pl 2>&1 |");
#output=<FILE>;
if(join('',#output)=~/syntax OK/)
{
printf("No Problem\n");
}
close(FILE);
See Test::Compile module, particularly pl_file_ok() function.

How to handle code coverage of both Perl scripts and modules?

I have a unique requirement of handling code coverage of my Perl scripts.
I have written a few Perl scripts which in turn uses a few Perl modules. My requirement is to use run these Perl scripts with different options they support and assess the code coverage of both Perl scripts and Perl modules.
So I am using Devel::Cover, Module::Build and Test::More from CPAN. It's all woring fine if I call functions inside Perl modules directly inside test script. But it's not working if I call the scripts directly (In this case I am not getting generated with code coverage of Perl modules and scripts both).
Here is my example test script using Test::More:
use strict;
use warnings;
use Test::More;
BEGIN { plan tests => 1 }
ok(sub {
my #args = ("ex4200fw","-query-fw","-i","192.168.168.1");
#print "# Executing #args \n";
`#args`;
my $rc = $? >> 8;
#print "# Return code: $rc \n";
$rc == 1
}->(),"Query Juniper EX4200 FW, incorrect IP address.\n");
Here ex4200fw (is in path) is the Perl script written by me which in turn calls dependent module updates.pm.
Do we have any tools to suite to this requirement?
Running Perl scripts and getting code coverage of both scripts and its dependent modules?
Can we accomplish the same using above CPAN modules?
Any sample script is much useful for me.
Gathering coverage statistics
To gather coverage statistics you need to use Devel::Cover. (If you can't directly change the source core of included scripts you can just specify -MDevel::Cover as a parameter to perl.)
So you should rather change your "test script" to add this parameter when calling other Perl script like following:
my #args = ("perl", "-MDevel::Cover", "ex4200fw","-query-fw","-i","192.168.168.1");
Or you can specify enviroment variable PERL5OPT=-MDevel::Cover before top test script is executed. In this case you'll not need to change any script source. Here is a small shell sample:
## run tests and gather coverage statistics
export PERL5OPT=-MDevel::Cover
perl test1.pl
perl test2.pl
...
Calculate result coverage
There is the cover utility which outputs all lines which were executed. You should run it after all tests are executed. Standard modules are excluded from the report by default.