The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
=head1 NAME

DBIx::Class::Migration::Tutorial::Testing - Test Your Database

=head1 GOAL

Let's take an interlude from creating migrations and turn to writing test
cases for your database.

It would help if you are familiar with L<Test::Most> and L<Test::DBIx::Class>
and with general Perl testing procedures.  You could also benefit from reviewing
our fixtures hook class L<Test::DBIx::Class::FixtureCommand::Population>.

=head1 Test your 1-2 Upgrade

When doing upgrades it would be great to have some automated tests in place so
that whoever does the upgrade can immediately verify that all is well.  Let's
add a test case now!

    touch t/upgrade-1to2.t

Then open the new files in the editor of choice and enter the following code:

    #!/usr/bin/env perl

    use Test::Most;
    use Test::DBIx::Class
      -schema_class=>'MusicBase::Schema',
      -fixture_class => '::Population',
      qw(Artist Country);

    plan skip_all => 'not correct schema version'
      if Schema->schema_version != 2;

    fixtures_ok ['all_tables'];

    is Country->count, 3, 'Correct Number of Countries';
    ok Artist->first->has_country, 'Artist has a country';

    done_testing;

This creates a basic test case that only runs for version 2 of the schema (this
is just testing that the version 2 update was correct after all).  It uses
L<Test::DBIx::Class> to automatically deploy a temporary test database (by
default it creates a C<SQLite> in-memory database) which reflects the current 
schema and then we populate the C<all_tables> fixtures using the utility class
L<DBIx::Class::Migration::Population> which is part of the L<DBIx::Class::Migration>
distribution.  (In this case, since we are using L<Test::DBIx::Class>, we are
using the fixture hook L<Test::DBIx::Class::FixtureCommand::Population>).

Before we can run the test case, we need to update our C<dist.ini>
file.  Open this is a text editor and change it to look like this:

    name    = DBIx-Class-Migration
    author  = John Napiorkowski <jjnapiork@cpan.org>
    license = Perl_5
    copyright_holder = John Napiorkowski
    copyright_year   = 2012
    abstract = Tutorial Application for DBIx-Class-Migration

    version = 0.001

    [@Basic]
    [Prereqs]
    DBIx::Class = 0
    DBIx::Class::Migration = 0

    [Prereqs / TestRequires]
    Test::Most = 0
    Test::DBIx::Class = 0

We just added a new section "[Prereqs / TestRequires]" and listed the two
testing modules.  Great, now install the new dependencies:

    dzil listdeps | cpanm

Perfect, we are now fully up to date and anyone that checks out our code can
also be sure to have all the right dependencies.  Let's run the test case:

    $ prove -lv t/upgrade-1to2.t 
    t/upgrade-1to2.t .. 
    Restored set all_tables to database
    ok 1 - Correct Number of Tests
    ok 2 - Artist has a country
    1..2
    ok
    All tests successful.
    Files=1, Tests=2,  1 wallclock secs ( ... )
    Result: PASS

So hopefully that was easier database testing than you might be used too. :)

=head1 Additional Domain Logic Testing

Let's create another test for the Artist ResultSet class.  You might have
wondered about this code, which you added way back at the start of the
tutorial:

C<lib/MusicBase/Schema/ResultSet/Artist.pm>

    package MusicBase::Schema::ResultSet::Artist;

    use strict;
    use warnings;
    use base 'DBIx::Class::ResultSet';

    sub has_more_than_one_cds {
      my $me = (my $self = shift)->current_source_alias;
      $self->search(
        {},
        {
          join=>['cd_rs'],
          '+select'=> [ { count => 'cd_rs.cd_id', -as => 'cd_count'} ],
          '+as'=> ['cd_count'],
          group_by=>["$me.artist_id"],
          having => { cd_count => { '>', 1 } }
        }
      );
    }

    1;

This is a bit of logic that just returns the set of Artist with more than one
cd.  This is the kind of custom resultset logic your application may require
and therefore you should have a test case.  Let's build one:

    touch t/more-than-1.t

Then open C<t/more-than-1.t> in your text editor and add this code:

    #!/usr/bin/env perl

    use Test::Most;
    use Test::DBIx::Class
      -schema_class=>'MusicBase::Schema',
      -fixture_class => '::Population',
      qw(Artist);

    fixtures_ok ['all_tables'];

    ok my $more_than_one_rs =  Artist->has_more_than_one_cds,
     'Got some artists';

    is $more_than_one_rs->count, 1,
      'Got expected number of artists with more than one CD';

    done_testing;

If you go back to the original fixture data, you'll see we only have one Artist
in the C<all_tables> fixture set that has more than one CD (Michael Jackson).

Obviously this is a pretty minimal test case, but it at least gets you started.
let's run it:

    $ prove -lv t/more-than-1.t 
    t/more-than-1.t .. 
    Restored set all_tables to database
    ok 1 - Got some artists
    ok 2 - Got expected number of artists with more than one CD
    1..2
    ok
    All tests successful.
    Files=1, Tests=2,  1 wallclock secs ( ... )
    Result: PASS

That's it for Testing!

=head1 SUMMARY

This was a short section, but important.  We explored how straightforward it is
to create meaningful test cases using our generated fixtures, if you use the
right tools to help you.  We also explored the idea of limiting test cases to
certain database versions, which will be an important thing for you to remember
as you continue moving forward with your database changes.

=head1 NEXT STEPS

Proceed to L<DBIx::Class::Migration::Tutorial::ThirdMigration>

=head1 AUTHOR

See L<DBIx::Class::Migration> for author information

=head1 COPYRIGHT & LICENSE

See L<DBIx::Class::Migration> for copyright and license information

=cut