NAME
Kelp::Test - Automated tests for a Kelp web app
SYNOPSIS
use MyApp;
use Kelp::Test;
use HTTP::Request::Common;
my $app = MyApp->new;
my $t = Kelp::Test->new( app => $app );
$t->request( GET '/path' )
->code_is(200)
->content_is("It works");
$t->request( POST '/api' )
->json_cmp({auth => 1});
DESCRIPTION
This module provides basic tools for testing a Kelp based web application. It is object oriented, and all methods return $self
, so they can be chained together. Testing is done by sending HTTP requests to an already built application and analyzing the response. Therefore, each test usually begins with the "request" method, which takes a single HTTP::Request parameter. It sends the request to the web app and saves the response as an HTTP::Response object.
ATTRIBUTES
app
The Kelp::Test object is instantiated with single attribute called app
. It is a reference to a Kelp based web app.
my $myapp = MyApp->new;
my $t = Kelp::Test->new( app => $myapp );
From this point on, all requests run with $t->request
will be sent to $app
.
psgi
This is only used when testing Kelp::Less apps. Since we don't have an application class to load, we need to load the app.psgi
file.
my $t = Kelp::Test->new( psgi => 'app.psgi' );
All testing methods work exactly the same way. Note that since we don't have control over how the Kelp
class is loaded, we may have to use the PLACK_ENV
environment variable to set different testing modes.
> PLACK_ENV=test prove -l
The above is the same as:
use Kelp::Less mode => 'test';
res
Each time $t-
request> is used to send a request, an HTTP::Response object is returned and saved in the res
attribute. You can use it to run tests, although as you will see, this module provides methods which make this a lot easier. It is recommended that you use the convenience methods rather than using res
.
$t->request( GET '/path' )
is $t->res->code, 200, "It's a success";
METHODS
request
request( $http_request )
Takes an HTTP::Request object and sends it to the application. When the HTTP::Response object is returned, it is initialized in the "res" attribute. It is very convenient to use HTTP::Request::Common in your test modules, so you can take advantage of the simplified syntax for creating an HTTP request.
$t->request( POST '/api', [ user => 'jane' ] );
This method returns $self
, so other methods can be chained after it.
code_is, code_isnt
code_is( $code, $test_name )
, code_isnt( $code, $test_name )
Tests if the last response returned a status code equal or not equal to $code
. An optional name of the test can be added as a second parameter.
$t->request( GET '/path' )->code_is(200);
$t->request( GET '/path' )->code_isnt(500);
content_is, content_isnt
content_is( $value, $test_name )
, content_isnt( $value, $test_name )
Tests if the last response returned content equal or not equal to $value
. An optional name of the test can be added as a second parameter.
$t->request( GET '/path' )->content_is("Ok.");
$t->request( GET '/path' )->content_isnt("Fail.");
content_like, content_unlike
content_like( $regexp, $test_name )
, content_unlike( $regexp, $test_name )
Tests if the last response returned content that matches or doesn't match $regexp
. An optional name of the test can be added as a second parameter.
$t->request( GET '/path' )->content_like(qr{Amsterdam});
$t->request( GET '/path' )->content_unlike(qr{Rotterdam});
content_type_is, content_type_isnt
content_type_is( $value, $test_name )
, content_type_isnt( $value, $test_name )
Tests if the last response's content-type header is equal or not equal to $value
. An optional name of the test can be added as a second parameter.
$t->request( GET '/path' )->content_type_is("text/plain");
$t->request( GET '/path' )->content_type_isnt("text/html");
header_is, header_isnt
header_is( $header, $value, $test_name )
, header_isnt( $header, $value, $test_name )
Tests if the last response returned a header $header
that is equal or not equal to $value
. An optional name of the test can be added as a second parameter.
$t->request( GET '/path' )->header_is( "Pragma", "no-cache" );
$t->request( GET '/path' )->header_isnt( "X-Check", "yes" );
header_like, header_unlike
header_like( $header, $regexp, $test_name )
, header_unlike( $header, $regexp, $test_name )
Tests if the last response returned a header $header
that matches or doesn't match $regexp
. An optional name of the test can be added as a second parameter.
$t->request( GET '/path' )->header_like( "Content-Type", qr/json/ );
$t->request( GET '/path' )->header_unlike( "Content-Type", qr/image/ );
json_cmp
json_cmp( $expected, $test_name )
This tests for two things: If the returned content-type
is application-json
, and if the returned JSON structure matches the structure specified in $expected
. To compare the two structures this method uses cmp_deeply
from Test::Deep, so you can use all the goodies from the SPECIAL-COMPARISONS-PROVIDED
section of the Test::Deep module.
$t->request( GET '/api' )->json_cmp(
{
auth => 1,
timestamp => ignore(),
info => subhashof( { name => 'Rick James' } )
}
);
An optional name of the test can be added as a second parameter.
note
note( $note )
Print a note, using the Test::More note
function.
$t->request( GET '/path' )
->note("Checking headers now")
->header_is( "Content-Type", qr/json/ );
diag_headers
Prints all headers for debugging purposes.
$t->request( GET '/path' )
->header_is( "Content-Type", qr/json/ )
->diag_headers();
diag_content
Prints the entire content for debugging purposes.
$t->request( GET '/path' )
->content_is("Well")
->diag_content();