Dancer2...Testing(3)
β¨ Dancer2::Manual::Testing β the vibe β¨
okay bestie, so this is Dancer2::Manual::Testing, from the User Contributed Perl Documentation crew, and it's literally your whole guide to writing tests for Dancer2. no cap. π
πΈ VERSION πΈ
version 2.2.1 β she's current, she's serving. π
π§ Basic application testing π§
so here's the tea: Dancer2 produces PSGI applications, which means you can very easily write tests using Plack::Test and just hand it your Dancer app as the app under test. iconic behavior, honestly. π¦
A basic test (which we also scaffold with dancer2) looks like this:
use strict;
use warnings;
use Test::More tests => 4;
use Plack::Test;
use HTTP::Request::Common;
use_ok('MyApp');
# create an application
my $app = MyApp->to_app;
isa_ok( $app, 'CODE' );
# create a testing object
my $test = Plack::Test->create($app);
# now you can call requests on it and get responses
# requests are of HTTP::Request
# responses are of HTTP::Response
# "GET" from HTTP::Request::Common creates an HTTP::Request object
my $response = $test->request( GET '/' );
# same as:
# my $response = $test->request( HTTP::Request->new( GET => '/' ) );
ok( $response->is_success, 'Successful request' );
is( $response->content, 'OK', 'Correct response content' );
go read the docs for HTTP::Request and HTTP::Request::Common to see all the different options for sending parameters, k? there's a lot going on in there and it's all useful. π
π Subtests π
Tests can be separated using Test::More's subtest functionality, which means you get multiple self-contained tests that don't affect each other. it's giving β¨organizationβ¨. no more one test ruining the whole mood.
Assuming we have a different app that we want to test:
# MyApp.pm
package MyApp;
use Dancer2;
set serializer => 'JSON';
my %users = (
jason => {
name => 'Jason',
likes => 'planes',
},
yanick => {
name => 'Yanick',
likes => 'orchids',
}
);
get '/:user' => sub {
my $user = route_parameters->get('user');
my $user_data = $users{$user};
if( $user_data ) {
return { user => $user_data };
}
status 404;
return {
error => 1,
message => 'user not found'
}
};
1;
This is an example of tests for that route, making sure we have the correct behavior with regard to the user parameter. lowkey this is the blueprint fr fr.
# param.t
use strict;
use warnings;
use Test::More;
use Plack::Test;
use HTTP::Request::Common;
use JSON qw/ decode_json /;
use MyApp;
# swap 'null' for 'note' to see the logs in your TAP output
MyApp::set( logger => 'null' );
my $test = Plack::Test->create( MyApp->to_app );
subtest 'An empty request' => sub {
my $res = $test->request( GET '/' );
is $res->code => 404, 'user not provided, so not found';
};
subtest 'Request with invalid user' => sub {
my $res = $test->request( GET '/sawyer_x' );
ok !$res->is_success, 'user not found';
is $res->code => 404, 'ressource not found';
is decode_json($res->content)->{message}, 'user not found', 'error message';
};
subtest 'Request with valid user' => sub {
my $res = $test->request( GET '/jason' );
ok $res->is_success, 'user found';
is decode_json($res->content)->{user}{likes}, 'planes', 'data present';
};
done_testing();
π Cookies π
To handle cookies β which are mostly used for maintaining sessions β the following modules can be used:
Test::WWW::Mechanize::PSGILWP::Protocol::PSGIHTTP::Cookies
Taking the previous test, assuming it actually creates and uses cookies for sessions (see cookie and perhaps Dancer2::Session::Cookie for more information on how to do that):
# ... all the use statements
use HTTP::Cookies;
my $jar = HTTP::Cookies->new;
my $test = Plack::Test->create( MyApp->to_app );
subtest 'Request with invalid user' => sub {
my $req = GET '/sawyer_x';
$jar->add_cookie_header($req);
my $res = $test->request($req);
ok !$res->is_success, 'Request failed';
$jar->extract_cookies($res);
ok !$jar->as_string, 'All cookies deleted';
};
subtest 'Request with user' => sub {
my $req = GET '/jason';
$jar->add_cookie_header($req);
my $res = $test->request($req);
ok $res->is_success, 'Successful request';
$jar->extract_cookies($res);
ok !$jar->as_string, 'All cookies deleted';
};
done_testing();
If you don't want to use an entire user agent for this test, you can use HTTP::Cookies to store cookies and then retrieve them:
use strict;
use warnings;
use Test::More tests => 3;
use Plack::Test;
use HTTP::Request::Common;
use HTTP::Cookies;
use_ok('MyApp');
my $url = 'http://localhost';
my $jar = HTTP::Cookies->new();
my $test = Plack::Test->create( MyApp->to_app );
subtest 'Create session' => sub {
my $res = $test->request( GET "$url/login" );
ok( $res->is_success, 'Successful login' );
# extract cookies from the response and store in the jar
$jar->extract_cookies($res);
};
subtest 'Check session' => sub {
my $req = GET "$url/logout";
# add cookies to the request
$jar->add_cookie_header($req);
my $res = $test->request($req);
ok( $res->is_success, 'Successful logout' );
like(
$res->content,
'Successfully logged out',
'Got correct log out content',
);
};
π«Ά please note bestie: the request URL must include scheme and host for the call toadd_cookie_headerinHTTP::Cookiesto work. that's not optional, that's the whole trick. π
π Accessing the configuration file π
By importing Dancer2 in the test files, there is full access to the configuration using the imported keywords:
use strict;
use warnings;
use Test::More;
use Plack::Test;
use HTTP::Request::Common;
use MyApp;
use Dancer2;
my $appname = config->{'appname'};
diag "Testing $appname";
# ...
π Plugins π
In order to test plugins, you can create an application on the spot, as part of the test script code, and use the plugin there. main character move honestly.
use strict;
use warnings;
use Test::More tests => 2;
use Plack::Test;
use HTTP::Request::Common;
{
package MyTestApp;
use Dancer2;
use Dancer2::Plugin::MyPlugin;
get '/' => sub { my_keyword };
}
my $test = Plack::Test->create( MyTestApp->to_app );
my $res = $test->request( GET '/' );
ok( $res->is_success, 'Successful request' );
is( $res->content, 'MyPlugin-MyKeyword', 'Correct content' );
π AUTHOR π
Dancer Core Developers β absolute legends, we stan. π«Ά
β COPYRIGHT AND LICENSE β
This software is copyright (c) 2026 by Alexis Sukrieh.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. (yes really, go wild, that's the whole license vibe.)
and that's the whole page, bestie!! this was Dancer2...Testing(3) from perl v5.42.3, dated 2026-09-20, part of the User Contributed Perl Documentation. go forth and test your apps, you've absolutely got this. πβ¨ππ¦πΈ
π¦ where this page comes from
- fedora 44: perl-Dancer2 2.2.1-1.fc44 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms