Catalyst Advent - Day 19 - Testing

Catalyst provides a convenient way of testing your application during development and before deployment in a real environment.

Catalyst::Test makes it possible to run the same tests both locally (without an external daemon) and against a remote server via HTTP.

Tests

Let's examine a skeleton application's t/ directory:

    mundus:~/MyApp chansen$ ls -l t/
    total 24
    -rw-r--r--  1 chansen  chansen   95 18 Dec 20:50 01app.t
    -rw-r--r--  1 chansen  chansen  190 18 Dec 20:50 02pod.t
    -rw-r--r--  1 chansen  chansen  213 18 Dec 20:50 03podcoverage.t

01app.t

Verifies that the application loads, compiles, and returns a successful response.

02pod.t

Verifies that all POD is free from errors. Only executed if the TEST_POD environment variable is true.

03podcoverage.t

Verifies that all methods/functions have POD coverage. Only executed if the TEST_POD environment variable is true.

Creating tests

    mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d  %s", $., $_ )'
    1  use Test::More tests => 2;
    2  use_ok( Catalyst::Test, 'MyApp' );
    3
    4  ok( request('/')->is_success );

The first line declares how many tests we are going to run, in this case two. The second line tests and loads our application in test mode. The fourth line verifies that our application returns a successful response.

Catalyst::Test exports two functions, request and get. Each can take three different arguments:

A string which is a relative or absolute URI.
    request('/my/path');
    request('http://www.host.com/my/path');

An instance of URI.
    request( URI->new('http://www.host.com/my/path') );

An instance of HTTP::Request.
    request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );

request returns an instance of HTTP::Response and get returns the content (body) of the response.

Running tests locally

    mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
    t/01app............ok                                                        
    t/02pod............ok                                                        
    t/03podcoverage....ok                                                        
    All tests successful.
    Files=3, Tests=4,  2 wallclock secs ( 1.60 cusr +  0.36 csys =  1.96 CPU)

CATALYST_DEBUG=0 ensures that debugging is off; if it's enabled you will see debug logs between tests.

TEST_POD=1 enables POD checking and coverage.

prove A command-line tool that makes it easy to run tests. You can find out more about it from the links below.

Running tests remotely

    mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
    t/01app....ok                                                                
    All tests successful.
    Files=1, Tests=2,  0 wallclock secs ( 0.40 cusr +  0.01 csys =  0.41 CPU)

CATALYST_SERVER=http://localhost:3000/ is the absolute deployment URI of your application. In CGI or FastCGI it should be the host and path to the script.

Test::WWW::Mechanize and Catalyst

Be sure to check out Test::WWW::Mechanize::Catalyst. It makes it easy to test HTML, forms and links. A short example of usage:

    use Test::More tests => 6;
    use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' );

    my $mech = Test::WWW::Mechanize::Catalyst->new;
    $mech->get_ok("http://localhost/", 'Got index page');
    $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
    ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
    ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
    ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );

Further Reading