How to run a Perl Dancer Test - perl

Reading through the Dancer::Test documentation made it seem straightforward to do a test, but I'm missing something. If I have the following Dancer application (WebApp.pm):
package WebApp;
use Dancer;
# declare routes/actions
get '/' => sub {
"Hello World";
};
dance;
and then the following testing file 001_base.t:
use strict;
use warnings;
use Test::More tests => 1;
use WebApp;
use Dancer::Test;
response_status_is [GET => '/'], 200, "GET / is found";
Then when I run the test: perl 001_base.t, the output is that the dancer script starts up:
Dancer 1.3132 server 7679 listening on http://0.0.0.0:3000
== Entering the development dance floor ...
But then waits. (This is the same as if I just run the code in WebApp.pm). What am I missing here? I guess I'm not running the test correctly.

You should remove dancer() from the WebApp.pm. Here is the correct content:
package WebApp;
use Dancer;
# declare routes/actions
get '/' => sub {
"Hello World";
};
1;
Then you test will pass.
The common way to create dancer apps is to declare all the routes in one or more .pm files and to have a file usually called app.psgi with the content:
#!/usr/bin/env perl
use Dancer;
use WebApp;
dance;
Then to start your web application you should run perl -Ilib app.psgi.

Related

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

Why isn't this perl cgi script redirecting?

I have a perl cgi script that is exactly the following:
#!/usr/bin/perl -w
use CGI;
$query = new CGI;
print $query->redirect("http://www.yahoo.com");
At the command line things look OK:
$perl test.pl
Status: 302 Moved
Location: http://www.yahoo.com
When I load it in the browser, http://localhost/cgi-bin/test.pl, the request gets aborted, and depending on the browser I get various messages:
Connection reset by server.
No data received.
The only research I could find on this issue, stated that a common problem is printing some data or header before the redirect call, but I am clearly not doing that here.
I'm hosting it from a QNX box with the default slinger server.
The code works fine on my machine, check the following
Check the error logs, eg: tail /var/log/http/error_log
Do the chmod/chown permissions match other working CGi scripts, compare using ls -l
Does printing the standard hello world work? Change your print statement to
print $query->header(), 'Hello World';
Add the following for better errors
use warnings;
use diagnostics;
use CGI::Carp 'fatalsToBrowser';
at the command line use slinger will return some basic use options. For logging you need both syslogd and -d enabled in slinger. Ie
slinger -d &
Then look to /var/log/syslog for errors

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 get the port that Mojolicious::Lite chooses?

Joel Berger posted this little program to start a web server to serve local files, and it works great:
use Mojolicious::Lite;
#ARGV = qw(daemon);
use Cwd;
app->static->paths->[0] = getcwd;
any '/' => sub {
shift->render_static('index.html');
};
app->start;
I prepopulated the command line in #ARGV because I forget to do that. When it starts, it gives a message telling you which port it chose, using 3000 if it can:
$ perl ~/bin/mojo_cwd
[Fri Mar 29 19:14:09 2013] [info] Listening at "http://*:3000".
Server available at http://127.0.0.1:3000.
I'd like to get that port programmatically so a test suite can know where to look for it, and I'd prefer not to do it by scrapping output. None of my experiments for this were useful and I think I was always going in the wrong direction. It appears that it doesn't choose the port until it starts, and once I call start, that's the end of it.
I don't want to specify the port myself, either.
This isn't an urgent matter. I have a current solution to this with another simple HTTP framework, but I've been looking at replacing most of that stuff with Mojo if I can. Since the old stuff still works, this is really just something nice to have rather than something in my way.
You can't, but the daemon command only binds to port 3000 and will not try anything else unless you tell it to. If you're using Test::Mojo you don't need to know the port in advance anyway, for anything else you can always wrap your application in a little Mojo::Server::Daemon script.
use Mojolicious::Lite;
use Mojo::IOLoop;
use Mojo::Server::Daemon;
get '/' => {text => 'Hello World!'};
my $port = Mojo::IOLoop->generate_port;
my $daemon = Mojo::Server::Daemon->new(
app => app,
listen => ["http://*:$port"]
);
$daemon->run;
With the --listen param you specify to your app where to listen:
use Mojolicious::Lite;
#ARGV = qw(daemon --listen http://*:5000);
use Cwd;
app->static->paths->[0] = getcwd;
any '/' => sub {
shift->render_static('index.html');
};
app->start;
You can access the port number within the app with $self->tx->local_port:
#!/usr/bin/env perl
use Mojolicious::Lite;
#ARGV = qw(daemon --listen http://*:5000);
use Cwd;
app->static->paths->[0] = getcwd;
any '/' => sub {
my $self = shift;
$self->render_text('port: '. $self->tx->local_port);
};
app->start if $ENV{MOJO_MODE} ne 'test';
1;
I like to test Mojolicious apps with Test::Mojo because you get access to the running app, for example, in a file t/test_mojo.t:
use strict;
use warnings;
use feature 'say';
use Test::More;
use Test::Mojo;
$ENV{MOJO_MODE} = 'test';
require "$FindBin::Bin/../test_mojo.pl";
my $t = Test::Mojo->new;
$t->get_ok('/')->status_is(200)->content_is('port: '.$t->tx->remote_port);
say 'local port: '. $t->tx->local_port; #as seen from the user-agent's perspective
say 'remote port:'. $t->tx->remote_port;
done_testing();
I'm not sure I correctly understood what you are trying to accomplish, but I hope this helps you.

How can I load a Perl module at runtime?

I would like to use the HTML::Template module. However, it is not installed on the server I'm using to develop CGI scripts.
Is it possible to load a module at runtime: I found the Template.pm file on my local Perl installation and uploaded the file to the server I'm using.
#!/usr/bin/perl -w
use CGI qw(:standard :html4);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
# use HTML::Template;
use Template;
# my $package = "HTML::Template";
# eval {
# (my $pkg = $package) =~ s|::|/|g; # require need a path
# require "$pkg.pm";
# import $package;
# };
# die $# if( $# );
# open the HTML template
my $template = HTML::Template->new(filename => 'test.tmpl');
# fill in some parameters in the template
$template->param(home => $ENV{HOME});
$template->param(path => $ENV{PATH});
# send the obligatory Content-Type
print "Content-Type: text/html\n\n";
# print the template
print $template->output;
Here is what I do:
cgi-bin/script.pl
cgi-bin/lib/HTML/Template.pm
In script.pl (unless you are running under mod_perl):
use FindBin qw( $Bin );
use File::Spec::Functions qw( catfile );
use lib catfile $Bin, 'lib';
use HTML::Template;
# The rest of your script
If HTML::Template is truly optional, read perldoc -f require.
See also How do I keep my own module/library directory? and What's the difference between require and use? in perlfaq8.
This is similar to Sinan's answer, but uses local::lib:
Set up your files as:
cgi-bin/script.pl
cgi-bin/lib/HTML/Template.pm
And in your script:
use strict;
use warnings;
use local::lib 'lib';
use HTML::Parser;
The advantage of local::lib is you can install modules from CPAN directly into a directory of your choosing:
perl -MCPAN -Mlocal::lib=lib -e 'CPAN::install("HTML::Parser")'
HTML::Template and Template are different Perl modules. If you want to use HTML::Template, you will need to use HTML::Template; at the top of the script to import that package.
Ensure that you copied the HTML/Template.pm file from your local machine to the server, rather than Template.pm.
I should have added this as an option, since I'm one of the maintainers of this module: App::FatPacker can be used to include a third-party module with your application when it ships, so it does not need to be installed separately in the deployment environment.
Yes it is. Look at Module::Runtime. I would install your HTML module though, even in a local install directory. It's probably less hassle.