We have created the following simple Mojolicious controller:
package SampleApp::Pages;
# $Id$
use strict;
use warnings;
our $VERSION = '0.01';
use Mojo::Base 'Mojolicious::Controller';
sub home {
my $self = shift;
$self->render( 'title' => 'Home' );
return;
}
sub contact {
my $self = shift;
$self->render( 'title' => 'Contact' );
return;
}
sub about {
my $self = shift;
$self->render( 'title' => 'About' );
return;
}
1;
The corresponding unit tests look as follows:
package Test::SampleApp::Pages;
# $Id$
use strict;
use warnings;
our $VERSION = '0.01';
use Carp;
use English '-no_match_vars';
use Readonly;
use Test::Mojo;
use Test::Most;
use base 'Test::Class';
Readonly my $SERVER_OK => 200;
sub startup : Tests(startup) {
eval {
require SampleApp;
SampleApp->import;
1;
} or Carp::croak($EVAL_ERROR);
return;
}
sub get_home : Tests(4) {
my $test = shift;
my $mojo = $test->mojo;
$mojo->get_ok('/pages/home')->status_is($SERVER_OK);
$mojo->text_is(
'title',
$test->base_title . ' | Home',
'... and should have the right title'
);
$mojo->content_like(
qr/<body>(?:\s*\S+\s*)+<\/body>/msx,
'... and should have a non-blank body'
);
return;
}
sub get_contact : Tests(3) {
my $test = shift;
my $mojo = $test->mojo;
$mojo->get_ok('/pages/contact')->status_is($SERVER_OK);
$mojo->text_is(
'title',
$test->base_title . ' | Contact',
'... and should have the right title'
);
return;
}
sub get_about : Tests(3) {
my $test = shift;
my $mojo = $test->mojo;
$mojo->get_ok('/pages/about')->status_is($SERVER_OK);
$mojo->text_is(
'title',
$test->base_title . ' | About',
'... and should have the right title'
);
return;
}
sub base_title {
my ( $self, $base_title ) = @_;
if ( defined $base_title ) {
$self->{base_title} = $base_title;
}
return $self->{base_title};
}
sub mojo {
my ( $self, $mojo ) = @_;
if ( defined $mojo ) {
$self->{mojo} = $mojo;
}
return $self->{mojo};
}
sub setup : Tests(setup) {
my $test = shift;
$test->base_title('Mojolicious Sample App');
$test->mojo( Test::Mojo->new( app => 'SampleApp', max_redirects => 1 ) );
return;
}
1;
To us, this is more like functionality testing rather than unit testing
Is there a way to call the home
method of the controller and test its output that doesn't require starting up a server instance via Test::Mojo
?
To test your controller's wiring, use code such as the following.
We begin t/pages.t
with familiar front matter.
use Mojolicious;
use Test::More;
Now create a testing subclass of SampleApp::Pages
that records calls to render
.
package TestingPages;
use Mojo::Base 'SampleApp::Pages';
has 'render_called';
has 'render_arg';
sub render {
my($self,%arg) = @_;
$self->render_called(1);
$self->render_arg({ %arg });
}
Your question used Test::Class
, so continue with that theme.
package Test::SampleApp::Pages;
use base 'Test::Class';
use Test::More;
Note that die
with no arguments propagates the most recent exception, so you don't have to write $@
explicitly.
sub startup : Test(startup) {
eval { require SampleApp::Pages; SampleApp::Pages->import; 1 } or die;
}
In setup
, instantiate the testing subclass, connect it to a Mojolicious instance, and turn off logging.
sub setup : Test(setup) {
my($self) = @_;
my $c = TestingPages->new(app => Mojolicious->new);
$c->app->log->path(undef);
$c->app->log->level('fatal');
$self->{controller} = $c;
}
In the home test, call the controller's home
method and inspect the results.
sub home : Tests(2) {
my($self) = @_;
my $c = $self->{controller};
$c->home;
is $c->render_called, 1, "render called";
is $c->render_arg->{title}, "Home", "correct title arg";
}
Finally, run your tests.
package main;
Test::SampleApp::Pages->runtests;
Output:
$ ./sampleapp.pl test Running tests from '/tmp/sampleapp/t'. t/pages.t .. ok All tests successful. Files=1, Tests=2, 1 wallclock secs ( 0.03 usr 0.02 sys + 0.24 cusr 0.03 csys = 0.32 CPU) Result: PASS
Now that you see how to do it, the question is whether it's worth all the trouble. Controllers should be simple wiring. Consider whether any complexity in a controller really belongs in a model where testing is much more straightforward.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With