NAME

bobby_tables4.pl

VERSION

version v4.1.1

Using Test::Chado with web applications

Using Test::Chado with web applications is not so different than using it with a distributable perl module. However, the most use will be to load fixtures before every test to check the GET request and to check for a database entry probably after every POST request. Here an example is given with Mojolicious framework for better understanding the use cases.

Setup

Install Mojolicious

cpanm Mojolicious

This guide assume to have you running v4.0+.

Create project folder

mkdir -p test_chado_with_mojo/t

The t folder will contain the test file.

Add Test::Chado as dependencies

Since web applications are generally not meant to packaged and/or distributable, a cpanfile is used for declaring dependencies. Save the below as cpanfile inside the project folder

requires 'Mojolicious', '4.0';
on 'test' => sub {
    requires 'Test::Chado', '1.0.0';
};

Install Test::Chado

cpanm .

Create application

Create a Mojolicious::Lite application in a file app.pl. First, we are going to create routes for creating and accession cvterms.

use Mojolicious::Lite;
use Mojo::Base -base;
use Bio::Chado::Schema;
use FindBin qw($Bin);
use File::Spec::Functions;

app->attr(
    schema => sub {
        my $dbname = catfile( $Bin, "db", "chado.sqlite" );
                return Bio::Chado::Schema->connect( "dbi:SQLite:dbname=$dbname", "", "" );
    }
);


post '/cvterms' => [ format => [qw/json/] ] => sub {
    my $self   = shift;
    my $params = $self->req->json;
    for my $p (qw/namespace id name/) {
        if ( not defined $params->{$p} ) {
            $self->res->message("Required parameter $p missing");
            $self->rendered(400);
            return;
        }
    }
    my ( $db, $id ) = split /:/, $params->{id};
    my $schema     = app->schema;
    my $cvterm_row = $schema->resultset('Cvterm')->create(
        {   name  => $params->{name},
            cv_id => $schema->resultset('Cv')
                ->find_or_create( { name => $params->{namespace} } )->cv_id,
            dbxref => {
                accession => $id,
                db_id     => $schema->resultset('Db')
                    ->find_or_create( { name => $db } )->db_id
            }
        }
    );

    $self->res->headers->location( "/cvterms/" . $params->{id} . ".json" );
    $self->rendered(201);
};

$app->start;

During the unit testing, the schema attribute will hold the Test::Chado schema and pass it along to the post route.

Now, write a unit test file(basic.t) inside the t/ folder.

use Test::More qw/no_plan/;
use Test::Mojo;
use Test::Chado;
use Test::Chado::Common;
use Module::Load;
use FindBin qw($Bin);

load "$Bin/../app.pl";

my $schema = chado_schema( load_fixture => 1 );
my $t = Test::Mojo->new;
$t->app->schema($schema);

my $post = $t->post_ok(
    '/cvterms.json' => json => {
        namespace => 'test-chado-mojoapp',
        id        => 'TC:000001',
        name      => 'test chado rocks'
    },
    "it should post the new cvterm"
);
$post->status_is( 201, "should get the correct response" );
$post->header_is(
    Location => "/cvterms/TC:000001.json",
    "should get the correct HTTP location header"
);
has_cvterm( $schema, "test chado rocks", "should have the new cvterm" );
has_dbxref( $schema, "000001", "should have the new dbxref" );

Run it

perl app.pl test

Running tests from '/home/cybersiddhu/Projects/Experiments/test_chado_with_mojo/t'.
t/basic.t .. 
ok 1 - POST /cvterms.json
ok 2 - should get the correct response
ok 3 - should get the correct HTTP location header
ok 4 - should have the new cvterm
ok 5 - should have the new dbxref
1..5
ok
All tests successful.
Files=1, Tests=5,  6 wallclock secs ( 0.02 usr  0.00 sys +  5.74 cusr  0.26 csys =  6.02 CPU)
Result: PASS

Now add a GET route and mojolicious test for it In app.pl

get '/cvterms/:id' => [ format => [qw/json/] ] => sub {
    my $self   = shift;
    my $schema = app->schema;
    my ( $db, $id ) = split /:/, $self->stash('id');
    my $row = $schema->resultset('Dbxref')
        ->search( { accession => $id }, { rows => 1 } )->single;
    if ( !$row ) {
        $self->rendered(401);
        return;
    }
    $self->render(
        json => {
            name => $row->cvterm->name,
            id   => $self->stash("id")
        }
    );
};

In basic.t

$t->get_ok("/cvterms/TC:000001.json")->status_is(200)
    ->json_is( { name => "test chado rocks", id => "TC:000001" },
        "should get correct name and id" );

perl app.pl test -v

Running tests from '/home/cybersiddhu/Projects/Experiments/test_chado_with_mojo/t'.
t/basic.t .. 
ok 1 - POST /cvterms.json
ok 2 - should get the correct response
ok 3 - should get the correct HTTP location header
ok 4 - should have the new cvterm
ok 5 - should have the new dbxref
ok 6 - GET /cvterms/TC:000001.json
ok 7 - 200 OK
ok 8 - should get correct name and id
1..8
ok
All tests successful.
Files=1, Tests=8,  6 wallclock secs ( 0.02 usr  0.01 sys +  5.82 cusr  0.27 csys =  6.12 CPU)
Result: PASS

Now, add few more tests for chado feature and featureloc tables entry In app.pl

post 'features' => [ format => [qw/json/] ] => sub {
    my $self   = shift;
    my $schema = app->schema;
    my $params = $self->req->json;
    for my $p (qw/name organism type/) {
        if ( not defined $params->{$p} ) {
            $self->res->message("Required parameter $p missing");
            $self->rendered(400);
            return;
        }
    }

    my $org_row
        = $schema->resultset('Organism')
        ->search( { common_name => $params->{organism} }, { rows => 1 } )
        ->single;
    my $feat_row = $schema->resultset('Feature')->create(
        {   name       => $params->{name},
            uniquename => $params->{name},
            type_id    => $schema->resultset('Cvterm')
                ->find( { name => $params->{type} } )->cvterm_id,
            organism_id => $org_row->organism_id
        }
    );
    if ( defined $params->{start} and defined $params->{end} ) {
        $feat_row->create_related( 'featureloc_features',
            { fmin => $params->{start}, fmax => $params->{end} } );
    }
    $self->res->headers->location( "/features/" . $params->{name} . ".json" );
    $self->rendered(201);

};

In app.pl, we have added a HTTP POST route features which creates an entry in feature table and add a featureloc if the values are provided. Now in basic.t, add few tests for this piece of code

my $post2 = $t->post_ok(
    '/features.json' => json => {
        name     => 'tcpl',
        type     => 'gene',
        organism => 'human'
    },
    "it should post the new feature"
);
$post2->status_is( 201, "should get the correct response" );
$post2->header_is(
    Location => "/features/tcpl.json",
    "should get the correct HTTP location header"
);
has_feature( $schema, 'tcpl', 'should have the new feature in database' );

perl app.pl test -v

ok 1 - POST /cvterms.json
ok 2 - should get the correct response
ok 3 - should get the correct HTTP location header
ok 4 - should have the new cvterm
ok 5 - should have the new dbxref
ok 6 - GET /cvterms/TC:000001.json
ok 7 - 200 OK
ok 8 - should get correct name and id
ok 9 - POST /features.json
ok 10 - should get the correct response
ok 11 - should get the correct HTTP location header
ok 12 - should have the new feature in database
1..12
ok
All tests successful.
Files=1, Tests=12,  6 wallclock secs ( 0.02 usr  0.00 sys +  5.81 cusr  0.18 csys =  6.01 CPU)
Result: PASS

Now test another feature with feature location. Append the following in basic.t

my $post3 = $t->post_ok(
    '/features.json' => json => {
        name     => 'panda',
        type     => 'contig',
        organism => 'human',
        start    => 48,
        end      => 500
    },
    "it should post the new feature with featureloc"
);
$post3->status_is( 201, "should get the correct response" );
$post3->header_is(
    Location => "/features/panda.json",
    "should get the correct HTTP location header"
);
has_feature( $schema, 'panda', 'should have the new feature in database' );
has_featureloc( $schema, 'panda',
    'should have the new feature with location in database' );
    
perl app.pl test -v


ok 1 - POST /cvterms.json
ok 2 - should get the correct response
ok 3 - should get the correct HTTP location header
ok 3 - should get the correct HTTP location header
ok 4 - should have the new cvterm
ok 5 - should have the new dbxref
ok 6 - GET /cvterms/TC:000001.json
ok 7 - 200 OK
ok 8 - should get correct name and id
ok 9 - POST /features.json
ok 10 - should get the correct response
ok 11 - should get the correct HTTP location header
ok 12 - should have the new feature in database
ok 13 - POST /features.json
ok 14 - should get the correct response
ok 15 - should get the correct HTTP location header
ok 16 - should have the new feature in database
ok 17 - should have the new feature with location in database
1..17
ok
All tests successful.
Files=1, Tests=17,  6 wallclock secs ( 0.02 usr  0.01 sys +  5.86 cusr  0.16 csys =  6.05 CPU)
Result: PASS

That's all folks!

AUTHOR

Siddhartha Basu <biosidd@gmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Siddhartha Basu.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.