How can I debug a single Perl unit test sub? - perl

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()

Related

Is there a need or how to write a test on main.pl which is not module and run it using Perl Devel cover

There are lots of material talking about writing coverage on module but how if I want to write a test for command runnable perl script (main.pl)?
Is there a need to write test for main.pl or I just need to write test for module will do?
Let's say I have these two scripts.
command runnable script
main.pl
import Halo;
&main;
sub main() {
my $a = 2;
my $b = 3;
my $c = Halo.add($a, $b);
print "a + b = $c\n";
}
==============================================
Perl module
Halo.pm
package Halo;
sub add() {
my ($class, $a, $b) = #_;
return $a + $b;
}
1;
==============================================
Run in command line:
perl main.pl
I suggest you research "unit" and "end-to-end" testing to understand the benefits of each. I would recommend that you do both. Testing your main script is easily done with "modulinos", allowing you to fairly painlessly tie into the existing Perl testing ecosystem.
From the synopsis: https://metacpan.org/pod/Devel::Cover#SYNOPSIS
$ perl -I. -MDevel::Cover main.pl
$ cover
You'll also need to change your code a bit. You'll need "use" instead of "import" and "Halo->add" instead of "Halo.add". (These changes are nothing to do with Devel::Cover.)

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;
}

Perl: What is the fastest way to run a perl script from within a perl script?

I am writing a Perl script that uses other Perl scripts (not mine). Some of them receive inputs with flags and some don't. Another thing that I need is to redirect the outputs of these scripts to different files. For example:
W\O flags: script1.pl arg1 arg2 arg3 > output1.log
W flags: script2.pl -a 1 -b 2 -c 3 > output2.log
Bottom line - I was using system() to do this, but then I found out that the script takes too long.
I tried doing this with do() but it didn't work (like here).
So what is the fastest way to achieve that?
You need to make your test script define a subroutine that executes everything you want to run, then make your main script read the Perl code of the test script and invoke that subroutine - so the test script will look something like this:
#!/usr/bin/env perl
#
# defines how to run a test
use strict;
use warnings;
sub test
{
my ($arg1, $arg2, $arg3) = #_;
# run the test
(...)
)
The main script:
#!/usr/bin/env perl
#
# runs all of the tests
use strict;
use warnings;
require 'testdef.pl'; # the other script
foreach (...)
{
(...)
test($arg1, $arg2, $arg3);
}
This is still a very basic way of doing it.
The proper way, as ikegami says, is to turn the test script into a module.
That will be worthwhile if you will be creating more test script files than just these two or if you want to install the scripts in various locations.
Use a multi argument system call: http://perldoc.perl.org/functions/system.html
This is not going to execute the shell, you could spare a few CPU cycles
system(qw(script1.pl arg1 arg2 arg3 > output1.log));
"As an optimization, may not call the command shell specified in
$ENV{PERL5SHELL} . system(1, #args) spawns an external process and
immediately returns its process designator, without waiting for it to
terminate. "
if you are not interested in the return status you could use exec instead or you could use fork/thread for paralel execution.

perl: run another script without exec/system

Is it possible to include/source another perl script, or launch it as a "sub"?
This works, but looks ugly:
test2.pl:
print "I'm in test2.pl; args: #ARGV\n";
test.pl:
#!/usr/bin/perl
use File::Temp qw/tempdir/;
use File::Copy qw/copy/;
my $tmplib;
use lib ($tmplib = tempdir()) . (
copy("./test2.pl", "$tmplib/test2.pm") ? "" : (die "$!")
);
use test2;
x
$ ./test.pl a b c
I'm in test2.pl; args: a b c
It sounds like you want the do operator, although it also sounds like very bad design.
This is what the documentation says.
do EXPR Uses the value of EXPR as a filename and executes the contents
of the file as a Perl script.
do 'stat.pl';
is just like
eval `cat stat.pl`;
You can use do to run another Perl script in the same interpreter:
do 'test2.pl';
This will reuse the command line parameters from the outer script. To pass different parameters, you can override #ARGV locally, like:
{
local #ARGV = qw(par1 par2 par3);
do 'test2.pl';
}

How to set breakpoint on a particular file in Perl program?

My Perl program looks like:
foo/
foo/bar/
for/bar/test.pm
foo.pm
foo/bar.pm
test.pl
and use perl test.pl to start the program.
I want to debug a sub in foo/bar/test.pm. How to set a breakpoint on that sub?
To debug a perl script, use the -d switch to invoke the debugger.
perl -d test.pl
Within the debugger you can use b <line no> to set a breakpoint in the current file. Sometimes it is a hassle to set a breakpoint in a file that hasn't been loaded yet or that was loaded a long time ago, so you can also put the line
$DB::single = 1;
anywhere in any perl program, and the debugger will break immediately after it executes that line. This is also a good way (the only way?) to set a breakpoint in code that will be run at compile time.
Just use the fully qualified name of the sub as the argument to b:
b foo::bar::test::subname
Example:
$ perl -d -e'use CGI; CGI->new'
...
main::(-e:1): use CGI; CGI->new
DB<1> b CGI::new
DB<2> r
CGI::new(.../CGI.pm:337):
337: my($class,#initializer) = #_;
DB<2> q
You can enter f Module.pm to tell the debugger to look at that particular module. Once you've done that, b line_number will stop at that line in Module.pm.
Once the original script has passed use Module, then b subroutine will stop at that subroutine. The only catch here is that you can't make your first two debugger commands f Module.pm; b subroutine because when the script begins, it hasn't passed use Module, so Module.pm hasn't loaded yet, which means that perl can't see that Module.pm has subroutine.