SlideShare una empresa de Scribd logo
1 de 46
Descargar para leer sin conexión
Testing
with
PostgreSQL
- First heard the term Polyglot Programmer during a
talk by John Anderson and found it described me
- Developed in Ruby, Python, Java, Groovy,
JavaScipt, C#, PHP, various SQL dialects, dabbled in
Go and of course perl
- I've been coding in perl since 1997
- started when I picked up AIX and needed to
automate some tasks
- haven't stopped automating since then
Hi, I'm Shawn.
• Polyglot Programmer
• First love is perl
• UNIX Geek
• Lots of database experience
• Currently on assignment with All Around the
World
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- described as a test runner however it doesn't
execute any test code
- Test::PostgreSQL allows testing with a throw away
database
- The 'test' here refers to not production or permanent
- I have been known to spin them up for debugging
from within reply
What is it?
• Test::PostgreSQL
• PostgreSQL runner for tests
• Test::PostgreSQL automatically sets up a
PostgreSQL instance in a temporary directory,
and destroys it when the perl script exits.
• Currently maintained by Toby Corkindale
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- pg_ctl is used by init scripts to initialize,
start, stop, or control a PostgreSQL server
- standard PostgreSQL port is 5432
- Automatically increments if the port is in
use (15433)
- can spawn multiple instances
How does it work
• Wrapper around the pg_ctl PostgreSQL controller
• Assigns a port if unused starting at 15432
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
Sqitch Basics
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Covered last month by Cees, can be covered in
more detail in a dedicated talk
- Sqitch is a tool for managing your DDL.
- Sqitch is an application not a module so it can be
used with any project, and for numerous databases
- PostgreSQL variants like Netezza and Greenplum
should also work
Why?
• Sqitch gives us a methodology to setup and tear
down test databases that match what is is in
production.
• App::Sqitch
• Written by David Wheeler
• Works with Firebird, MySQL, Oracle, PostgreSQL,
SQLite, Vertica
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Creates sqitch.conf, sqitch.plan, deploy/, revert/, verify/
- Create the first migration, creating files in the deploy/, revert/, verify/ with
the migration name
- A word on running with carton, I received an error message Cannot
find deploy template the work around was to add
template_directory = local/etc/sqitch/templates to
sqitch.conf in the add section
Fast Start
• Initialize sqitch environment
sqitch init test_postgresql --engine pg
• Creating a migration
sqitch add user_table -n 'Add user table.'
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Simple user table
- quick note about TEXT columns, in PostgreSQL there is no
performance or storage benefit from using a fixed width VARCHAR
column, so just use TEXT
- PostgreSQL reserved words, user is a reserved word, and will
throw an error unless double quoted "user"
- while database connectivity can be specified in the
sqitch.conf file, personal preference is to use it on the
command line.
Deploying
Creates file deploy/user_table.sql
-- Deploy test_postgresql:user_table to pg
BEGIN;
CREATE TABLE "user" (
user_id SERIAL PRIMARY KEY,
user_name TEXT UNIQUE,
password TEXT
);
COMMIT;
Executed by issuing:
sqitch deploy db:pg:test_db
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- ROLLBACK verifications can change data, and at the end
they will be undone by default.
- Table creation verification is simple, and if it didn't create,
there would be a SQL error during deployment.
- More advanced verification for procedures and table
alters
Verifying
Creates file verify/user_table.sql.
-- Verify test_postgresql:user_table on pg
BEGIN;
SELECT 1/COUNT(0)
FROM information_schema.tables
WHERE table_name = 'user'
;
ROLLBACK;
Executed by issuing:
sqitch verify db:pg:test_db
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- When you need to remove changes
- Reverting is destructive and the only way
to go back is through restoring
Reverting
Creates file revert/user_table.sql.
-- Revert test_postgresql:user_table from pg
BEGIN;
DROP TABLE "user";
COMMIT;
Executed by issuing:
sqitch revert db:pg:test_db
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Overtime changes aren't backward compatible and running sqitch
verify will break.
- During these times using the --verify switch during deployment
tells sqitch to verify what it's deploying, not what has already been
deployed.
Verifying during deployment
Executed by issuing:
sqitch deploy --verify db:pg:test_db
Verify each migration after deploying.
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
The
Test::PostgreSQL
Module
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- While the name suggests test, it's really a temporary
PostgreSQL database
Not just for
testing!
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Avoid dbicdump creating
my_tmp_table_bkup
- Force truth into sqitch
DBIC Schema Update Utility
• Helps keep sqitch deployments and DBIC schemas
in sync
• Ensures that developer temporary changes don't
make their way into DBIC schemas
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Creates a new PostgreSQL database
- Deploys sqitch database migrations to it
- Runs dbicdump to create the DBIC
schema packages
- This code is going to become familiar
dbic_update.pl
use App::Sqitch;
use App::Sqitch::Command::deploy;
use App::Sqitch::Command::verify;
use Test::PostgreSQL;
my $db = Test::PostgreSQL->new;
my $sqitch = App::Sqitch->new(
options => {
engine => 'pg',
},
);
my $deploy = App::Sqitch::Command::deploy->new(
sqitch => $sqitch,
target => $db->uri,
);
$deploy->execute();
say $db->dsn;
my $dsn = $db->dsn;
$dsn =~ s/^dbi/dbi/i;
$dsn =~ s/dbname=/database=/i;
system "dbicdump -o dump_directory=./lib MyApp::Schema '$dsn'";
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- calling sqitch from within a script/module was
added in 0.996 with a patch from Chris Prather
- used to error out on a Moose error
Automating Sqitch for Testing
Requires App::Sqitch version 0.996
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- going to create a temporary database
- deploy and verify each step in turn
- test that reverting each step succeeds
- there's no test at the end to make sure
the database is back to an empty state
Test Sqitch automation
• Creates a test database
• Runs deploy and verify steps
• Reverts changes
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- There is the option of executing the command line via
system, however I find this method cleaner, even though
it uses more modules up front
- Test modules and the App::Sqitch internals
Setting up the test
use Test::PostgreSQL;
use Test::Most;
use App::Sqitch;
use App::Sqitch::Target;
use App::Sqitch::Command::deploy;
use App::Sqitch::Command::verify;
use App::Sqitch::Command::revert;
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Calling new on Test::PostgreSQL starts the
PostgreSQL instance
Setting up the database
my $db = Test::PostgreSQL->new;
my $sqitch = App::Sqitch->new(
options => {
engine => 'pg',
},
);
my $target = App::Sqitch::Target->new( sqitch => $sqitch);
my $plan = $target->plan;
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Tell Sqitch that we want to execute using a pg engine
- Sqitch classes are a hierarchy, need to build each
individual object to proceed
Setting up Sqitch
my $db = Test::PostgreSQL->new;
my $sqitch = App::Sqitch->new(
options => {
engine => 'pg',
},
);
my $target = App::Sqitch::Target->new( sqitch => $sqitch);
my $plan = $target->plan;
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Set the Sqitch target and read in the plan file
Getting the Sqitch plan
my $db = Test::PostgreSQL->new;
my $sqitch = App::Sqitch->new(
options => {
engine => 'pg',
},
);
my $target = App::Sqitch::Target->new( sqitch => $sqitch);
my $plan = $target->plan;
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- plan file contents are not necessarily in order
- The $plan iterator is used to get the next step
in the plan
- Run a deploy on each step via deploy
command
- to_change will process the plan up to and
including the specified change
Looping through the plan
while ( my $change = $plan->next ) {
my $deploy = App::Sqitch::Command::deploy->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name;
my $verify = App::Sqitch::Command::verify->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $verify->execute() } 'verify sqitch plan';
push @revert, $change->name;
}
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Run a verify on each step via verify command
- to_change will process the verify plan up to
and including the specified change
Looping through the plan
while ( my $change = $plan->next ) {
my $deploy = App::Sqitch::Command::deploy->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name;
my $verify = App::Sqitch::Command::verify->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $verify->execute() } 'verify sqitch plan';
push @revert, $change->name;
}
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Store the change to be able to revert it in reverse order
later
Looping through the plan
while ( my $change = $plan->next ) {
my $deploy = App::Sqitch::Command::deploy->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name;
my $verify = App::Sqitch::Command::verify->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $verify->execute() } 'verify sqitch plan';
push @revert, $change->name;
}
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- If we try to revert the last change, sqitch will complain that
there's nothing further deployed.
Looping through the plan
pop @revert;
while ( my $change_name = pop @revert ) {
my $verify = App::Sqitch::Command::revert->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change_name,
no_prompt => 1,
);
lives_ok { $verify->execute() } 'revert sqitch plan to ' . $change_name;
}
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- We've built and verified the entire database
structure and now we'll tear it down
- Run the revert command on each change
Looping through the plan
pop @revert;
while ( my $change_name = pop @revert ) {
my $verify = App::Sqitch::Command::revert->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change_name,
no_prompt => 1,
);
lives_ok { $verify->execute() } 'revert sqitch plan to ' . $change_name;
}
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- highlevel of the module with methods
- The skeleton provides methods to be used
during your testing: db, dsn, dbh, dbic
- Now step into each of the methods
Test Module Skeleton
package MyApp::Test::PostgreSQL;
use strict;
use warnings;
use App::Sqitch;
use Moose;
use DBI;
use Test::PostgreSQL;
use DateTime;
use MyApp::Schema;
use App::Sqitch::Command::deploy;
+-- 6 lines: has db => (-----------------------------------------------------------------------------------------
+-- 6 lines: has dsn => (----------------------------------------------------------------------------------------
+-- 15 lines: has dbh => (----------------------------------------------------------------------------------------
+-- 9 lines: has dbic => (---------------------------------------------------------------------------------------
+-- 11 lines: has sqitch => (-------------------------------------------------------------------------------------
+-- 7 lines: has fixtures => (-----------------------------------------------------------------------------------
+-- 10 lines: has perm_fixtures => (------------------------------------------------------------------------------
+-- 8 lines: sub deploy {----------------------------------------------------------------------------------------
no Moose;
__PACKAGE__->meta->make_immutable;
1;
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- access to the Test::PostgreSQL object
- not really needed during testing directly
MyApp::Test::PostgreSQL::db
has db => (
is => 'ro',
isa => 'Test::PostgreSQL',
lazy => 1,
default => sub { Test::PostgreSQL->new },
);
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- returns the dsn created by Test::PostgreSQL
- simple string that can be used to create
additional connections
- Create new DBI connections, hand over to
applications
MyApp::Test::PostgreSQL::dsn
has dsn => (
is => 'ro',
isa => 'Str',
lazy => 1,
default => sub { return $_[0]->db->dsn },
);
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- returns a DBI database handle connected to the
Test::PostgreSQL instance.
- this is a shared connection, transactions might cause
issues, if in doubt start a new connection
MyApp::Test::PostgreSQL::dbh
has dbh => (
is => 'ro',
lazy => 1,
default => sub {
DBI->connect(
$_[0]->dsn,
undef, undef,
{
pg_enable_utf8 => 1,
RaiseError => 1,
AutoCommit => 1,
}
)
}
);
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- returns a DBIC Schema object
- uses the Schema object from your
application
MyApp::Test::PostgreSQL::dbic
has dbic => (
is => 'ro',
lazy => 1,
default => sub {
my ($self) = @_;
MyApp::Schema->connect({
dbh_maker => sub { $self->dbh },
quote_names => 1,
});
}
);
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Data to add to the database for testing
- Written by Curtis "Ovid" Poe
- While stating that it's Alpha software,
we use it a lot
Fixtures
• DBIx::Class::EasyFixture
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- there's a lot of details here and the packages can get
quite large
- this example shows the necessities, real world the
%definition_for hash is huge
- going to break this down and explain what's going on
The Fixture Package
package MyApp::Test::Fixtures;
use Moose;
extends 'DBIx::Class::EasyFixture';
use Crypt::Bcrypt::Easy ();
my %definition_for = (
basic_user => {
new => 'User',
using => {
user_name => 'tester',
password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 )
},
next => [qw(user_entry)],
},
user_entry => {
new => 'Entry',
using => {
user_id => 'basic_user',
entry => 'This is my entry.',
},
},
);
sub get_definition {
my ( $self, $name ) = @_;
return $definition_for{$name};
}
sub all_fixture_names { return keys %definition_for }
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- This is the data definition, but more to come
We'll come back to this
package MyApp::Test::Fixtures;
use Moose;
extends 'DBIx::Class::EasyFixture';
use Crypt::Bcrypt::Easy ();
my %definition_for = (
basic_user => {
new => 'User',
using => {
user_name => 'tester',
password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 )
},
next => [qw(user_entry)],
},
user_entry => {
new => 'Entry',
using => {
user_id => 'basic_user',
entry => 'This is my entry.',
},
},
);
sub get_definition {
my ( $self, $name ) = @_;
return $definition_for{$name};
}
sub all_fixture_names { return keys %definition_for }
Let's ignore this section for now and return after looking at the basics.
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- DBIx::Class:EasyFixture requires that
get_definition and all_fixture_names be
overridden.
- These are the simplest definitions and can be reused
Required overrides
package MyApp::Fixtures;
use Moose;
extends 'DBIx::Class::EasyFixture';
use Crypt::Bcrypt::Easy ();
my %definition_for = (
basic_user => {
new => 'User',
using => {
user_name => 'tester',
password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 )
},
next => [qw(user_entry)],
},
user_entry => {
new => 'Entry',
using => {
user_id => 'basic_user',
entry => 'This is my entry.',
},
},
);
sub get_definition {
my ( $self, $name ) = @_;
return $definition_for{$name};
}
sub all_fixture_names { return keys %definition_for }
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- basic_user is a unique identifier
- new is the result set full package name is
MyApp::Schema::Result::User
- using is the record data
- able to mix in function calls like password
- next and requires can be used to
specify fixture dependencies
- STRINGREF is a reference to an existing
Data definition
...
my %definition_for = (
basic_user => {
new => 'User',
using => {
user_name => 'tester',
password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 )
},
next => [qw(user_entry)],
},
user_entry => {
new => 'Entry',
using => {
user_id => 'basic_user',
entry => 'This is my entry.',
},
},
);
...
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Access to the fixtures object
- Fixtures by default are written in one
transaction
MyApp::Test::PostgreSQL::fixtures
has fixtures => (
is => 'ro',
lazy => 1,
default => sub {
MyApp::Test::Fixtures->new( { schema => $_[0]->dbic } )
},
);
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Access to the fixtures object
- Disable transactions so that other sessions
can access the data
MyApp::Test::PostgreSQL::perm_fixtures
has perm_fixtures => (
is => 'ro',
lazy => 1,
default => sub {
MyApp::Test::Fixtures->new( {
schema => $_[0]->dbic,
no_transactions => 1,
} )
},
);
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- At this point you have a populated database
- New connections can access the database via
$dsn
- diag $dsn is useful for connecting with an
external client
- full access to the MyApp::Test::PostgreSQL
methods for access to dbh, and dbic
Actually writing tests
use MyApp::Test::PostgreSQL;
use MyApp::Test::Fixtures;
use Test::Most;
my $db = MyApp::Test::PostgreSQL->new;
my $dbic = $db->dbic;
my $dsn = $db->dsn;
$dsn =~ s/^dbi/dbi/i;
diag $dsn;
lives_ok { $db->deploy } 'database set up';
$db->perm_fixtures->load('basic_user');
# Add all your test methods here
$db->perm_fixtures->unload;
done_testing;
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- t/lib required as that's where the MyApp::Test
modules live
Running tests
prove -lv -I t/lib t/simple.t
t/simple.t .. # dbi:Pg:dbname=test;host=127.0.0.1;port=15432;user=postgres
Adding registry tables to db:postgresql://postgres@127.0.0.1:15432/test
Deploying changes to db:postgresql://postgres@127.0.0.1:15432/test
+ user_table ... ok
+ entry_table .. ok
ok 1 - database set up
1..1
Pg refused to die gracefully; killing it violently.
Pg really didn't die.. WTF?
ok
All tests successful.
Files=1, Tests=1, 20 wallclock secs ( 0.03 usr 0.02 sys + 2.53 cusr 1.31 csys = 3.89 CPU)
Result: PASS
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Yeah, these error messages are interesting
- non-impacting, might have something to
do with fixtures
WTF?
prove -lv -I t/lib t/simple.t
t/simple.t .. # dbi:Pg:dbname=test;host=127.0.0.1;port=15432;user=postgres
Adding registry tables to db:postgresql://postgres@127.0.0.1:15432/test
Deploying changes to db:postgresql://postgres@127.0.0.1:15432/test
+ user_table ... ok
+ entry_table .. ok
ok 1 - database set up
1..1
Pg refused to die gracefully; killing it violently.
Pg really didn't die.. WTF?
ok
All tests successful.
Files=1, Tests=1, 20 wallclock secs ( 0.03 usr 0.02 sys + 2.53 cusr 1.31 csys = 3.89 CPU)
Result: PASS
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
- Written by Curtis "Ovid" Poe
- Originally written by Curtis "Ovid" Poe, and now
maintained by Dave Rolsky
- Haven't used Test::mongod though it's on my list of
modules to try and tests to migrate, written by co-worker
Jesse Shy
More Reading
• DBIx::Class::EasyFixture::Tutorial - It's
complicated
• Test::Class::Moose - Serious testing for
serious Perl
• Test::mongod - run a temporary instance of
MongoDB by Jesse Shy
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
References
• Test::PostgreSQL
• Reply
• App::Sqitch
• DBIx::Class::EasyFixture
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
MoreTesting with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
Updating DBIC Schemas
#!/bin/env perl
use v5.20;
use autodie ':all';
use App::Sqitch;
use App::Sqitch::Command::deploy;
use App::Sqitch::Command::verify;
use Test::PostgreSQL;
my $db = Test::PostgreSQL->new;
my $sqitch = App::Sqitch->new(
options => {
engine => 'pg',
},
);
my $deploy = App::Sqitch::Command::deploy->new(
sqitch => $sqitch,
target => $db->uri,
);
$deploy->execute();
say $db->dsn;
my $dsn = $db->dsn;
$dsn =~ s/^dbi/dbi/i;
$dsn =~ s/dbname=/database=/i;
system "dbicdump -o dump_directory=./lib MyApp::Schema '$dsn'";
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
sqitch.t
use Test::PostgreSQL;
use Test::Most;
use App::Sqitch;
use App::Sqitch::Target;
use App::Sqitch::Command::deploy;
use App::Sqitch::Command::verify;
use App::Sqitch::Command::revert;
bail_on_fail;
my $db = Test::PostgreSQL->new;
my $sqitch = App::Sqitch->new(
options => {
engine => 'pg',
},
);
my $target = App::Sqitch::Target->new( sqitch => $sqitch);
my $plan = $target->plan;
my ( @revert );
while ( my $change = $plan->next ) {
my $deploy = App::Sqitch::Command::deploy->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name;
my $verify = App::Sqitch::Command::verify->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change->name,
);
lives_ok { $verify->execute() } 'verify sqitch plan';
push @revert, $change->name;
}
pop @revert;
while ( my $change_name = pop @revert ) {
my $verify = App::Sqitch::Command::revert->new(
sqitch => $sqitch,
target => $db->uri,
to_change => $change_name,
no_prompt => 1,
);
lives_ok { $verify->execute() } 'revert sqitch plan to ' . $change_name;
}
done_testing();
Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti

Más contenido relacionado

La actualidad más candente

La actualidad más candente (20)

Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)
 
Continuous Integration and DevOps with Open Build Service(OBS)
Continuous Integration and DevOps with Open Build Service(OBS)Continuous Integration and DevOps with Open Build Service(OBS)
Continuous Integration and DevOps with Open Build Service(OBS)
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
 
Continuous Infrastructure: Modern Puppet for the Jenkins Project - PuppetConf...
Continuous Infrastructure: Modern Puppet for the Jenkins Project - PuppetConf...Continuous Infrastructure: Modern Puppet for the Jenkins Project - PuppetConf...
Continuous Infrastructure: Modern Puppet for the Jenkins Project - PuppetConf...
 
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
 
Using the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM DevelopmentUsing the Groovy Ecosystem for Rapid JVM Development
Using the Groovy Ecosystem for Rapid JVM Development
 
Aug penguin16
Aug penguin16Aug penguin16
Aug penguin16
 
Simple Build Tool
Simple Build ToolSimple Build Tool
Simple Build Tool
 
Puppetconf 2015 - Puppet Reporting with Elasticsearch Logstash and Kibana
Puppetconf 2015 - Puppet Reporting with Elasticsearch Logstash and KibanaPuppetconf 2015 - Puppet Reporting with Elasticsearch Logstash and Kibana
Puppetconf 2015 - Puppet Reporting with Elasticsearch Logstash and Kibana
 
Test-Driven Infrastructure with Ansible, Test Kitchen, Serverspec and RSpec
Test-Driven Infrastructure with Ansible, Test Kitchen, Serverspec and RSpecTest-Driven Infrastructure with Ansible, Test Kitchen, Serverspec and RSpec
Test-Driven Infrastructure with Ansible, Test Kitchen, Serverspec and RSpec
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014
 
Testing Your Automation Code (Docker Version)
Testing Your Automation Code (Docker Version)Testing Your Automation Code (Docker Version)
Testing Your Automation Code (Docker Version)
 
Test Driven Development with Puppet
Test Driven Development with Puppet Test Driven Development with Puppet
Test Driven Development with Puppet
 
Супер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOSСупер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOS
 
Killer R10K Workflow - PuppetConf 2014
Killer R10K Workflow - PuppetConf 2014Killer R10K Workflow - PuppetConf 2014
Killer R10K Workflow - PuppetConf 2014
 
Workshop: Know Before You Push 'Go': Using the Beaker Acceptance Test Framewo...
Workshop: Know Before You Push 'Go': Using the Beaker Acceptance Test Framewo...Workshop: Know Before You Push 'Go': Using the Beaker Acceptance Test Framewo...
Workshop: Know Before You Push 'Go': Using the Beaker Acceptance Test Framewo...
 
Continous delivery with sbt
Continous delivery with sbtContinous delivery with sbt
Continous delivery with sbt
 
Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!
 
DevOps Hackathon: Session 3 - Test Driven Infrastructure
DevOps Hackathon: Session 3 - Test Driven InfrastructureDevOps Hackathon: Session 3 - Test Driven Infrastructure
DevOps Hackathon: Session 3 - Test Driven Infrastructure
 
Virtual Bolt Workshop, 5 May 2020
Virtual Bolt Workshop, 5 May 2020Virtual Bolt Workshop, 5 May 2020
Virtual Bolt Workshop, 5 May 2020
 

Similar a Testing with PostgreSQL

Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverageTesting NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
mlilley
 
Effective testing for spark programs Strata NY 2015
Effective testing for spark programs   Strata NY 2015Effective testing for spark programs   Strata NY 2015
Effective testing for spark programs Strata NY 2015
Holden Karau
 
Power on, Powershell
Power on, PowershellPower on, Powershell
Power on, Powershell
Roo7break
 
Agile db testing_techniques
Agile db testing_techniquesAgile db testing_techniques
Agile db testing_techniques
Tarik Essawi
 

Similar a Testing with PostgreSQL (20)

Continuous Integration Testing in Django
Continuous Integration Testing in DjangoContinuous Integration Testing in Django
Continuous Integration Testing in Django
 
Jenkins Pipelines
Jenkins PipelinesJenkins Pipelines
Jenkins Pipelines
 
(Declarative) Jenkins Pipelines
(Declarative) Jenkins Pipelines(Declarative) Jenkins Pipelines
(Declarative) Jenkins Pipelines
 
Agile Swift
Agile SwiftAgile Swift
Agile Swift
 
Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverageTesting NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
 
Automated testing with Drupal
Automated testing with DrupalAutomated testing with Drupal
Automated testing with Drupal
 
Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023Leveling Up With Unit Testing - php[tek] 2023
Leveling Up With Unit Testing - php[tek] 2023
 
Effective testing for spark programs Strata NY 2015
Effective testing for spark programs   Strata NY 2015Effective testing for spark programs   Strata NY 2015
Effective testing for spark programs Strata NY 2015
 
How to integrate_custom_openstack_services_with_devstack
How to integrate_custom_openstack_services_with_devstackHow to integrate_custom_openstack_services_with_devstack
How to integrate_custom_openstack_services_with_devstack
 
Development Setup of B-Translator
Development Setup of B-TranslatorDevelopment Setup of B-Translator
Development Setup of B-Translator
 
MySQL Utilities -- PyTexas 2015
MySQL Utilities -- PyTexas 2015MySQL Utilities -- PyTexas 2015
MySQL Utilities -- PyTexas 2015
 
Riga Dev Day - Automated Android Continuous Integration
Riga Dev Day - Automated Android Continuous IntegrationRiga Dev Day - Automated Android Continuous Integration
Riga Dev Day - Automated Android Continuous Integration
 
Openshift cheat rhce_r3v1 rhce
Openshift cheat rhce_r3v1 rhceOpenshift cheat rhce_r3v1 rhce
Openshift cheat rhce_r3v1 rhce
 
Power on, Powershell
Power on, PowershellPower on, Powershell
Power on, Powershell
 
Agile db testing_techniques
Agile db testing_techniquesAgile db testing_techniques
Agile db testing_techniques
 
Neutron upgrades
Neutron upgradesNeutron upgrades
Neutron upgrades
 
Unit Testing from Setup to Deployment
Unit Testing from Setup to DeploymentUnit Testing from Setup to Deployment
Unit Testing from Setup to Deployment
 
Zero Downtime Deployment with Ansible
Zero Downtime Deployment with AnsibleZero Downtime Deployment with Ansible
Zero Downtime Deployment with Ansible
 
WordPress Acceptance Testing, Solved!
WordPress Acceptance Testing, Solved!WordPress Acceptance Testing, Solved!
WordPress Acceptance Testing, Solved!
 
Make BDD great again
Make BDD great againMake BDD great again
Make BDD great again
 

Último

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Último (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 

Testing with PostgreSQL

  • 2. - First heard the term Polyglot Programmer during a talk by John Anderson and found it described me - Developed in Ruby, Python, Java, Groovy, JavaScipt, C#, PHP, various SQL dialects, dabbled in Go and of course perl - I've been coding in perl since 1997 - started when I picked up AIX and needed to automate some tasks - haven't stopped automating since then Hi, I'm Shawn. • Polyglot Programmer • First love is perl • UNIX Geek • Lots of database experience • Currently on assignment with All Around the World Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 3. - described as a test runner however it doesn't execute any test code - Test::PostgreSQL allows testing with a throw away database - The 'test' here refers to not production or permanent - I have been known to spin them up for debugging from within reply What is it? • Test::PostgreSQL • PostgreSQL runner for tests • Test::PostgreSQL automatically sets up a PostgreSQL instance in a temporary directory, and destroys it when the perl script exits. • Currently maintained by Toby Corkindale Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 4. - pg_ctl is used by init scripts to initialize, start, stop, or control a PostgreSQL server - standard PostgreSQL port is 5432 - Automatically increments if the port is in use (15433) - can spawn multiple instances How does it work • Wrapper around the pg_ctl PostgreSQL controller • Assigns a port if unused starting at 15432 Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 5. Sqitch Basics Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 6. - Covered last month by Cees, can be covered in more detail in a dedicated talk - Sqitch is a tool for managing your DDL. - Sqitch is an application not a module so it can be used with any project, and for numerous databases - PostgreSQL variants like Netezza and Greenplum should also work Why? • Sqitch gives us a methodology to setup and tear down test databases that match what is is in production. • App::Sqitch • Written by David Wheeler • Works with Firebird, MySQL, Oracle, PostgreSQL, SQLite, Vertica Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 7. - Creates sqitch.conf, sqitch.plan, deploy/, revert/, verify/ - Create the first migration, creating files in the deploy/, revert/, verify/ with the migration name - A word on running with carton, I received an error message Cannot find deploy template the work around was to add template_directory = local/etc/sqitch/templates to sqitch.conf in the add section Fast Start • Initialize sqitch environment sqitch init test_postgresql --engine pg • Creating a migration sqitch add user_table -n 'Add user table.' Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 8. - Simple user table - quick note about TEXT columns, in PostgreSQL there is no performance or storage benefit from using a fixed width VARCHAR column, so just use TEXT - PostgreSQL reserved words, user is a reserved word, and will throw an error unless double quoted "user" - while database connectivity can be specified in the sqitch.conf file, personal preference is to use it on the command line. Deploying Creates file deploy/user_table.sql -- Deploy test_postgresql:user_table to pg BEGIN; CREATE TABLE "user" ( user_id SERIAL PRIMARY KEY, user_name TEXT UNIQUE, password TEXT ); COMMIT; Executed by issuing: sqitch deploy db:pg:test_db Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 9. - ROLLBACK verifications can change data, and at the end they will be undone by default. - Table creation verification is simple, and if it didn't create, there would be a SQL error during deployment. - More advanced verification for procedures and table alters Verifying Creates file verify/user_table.sql. -- Verify test_postgresql:user_table on pg BEGIN; SELECT 1/COUNT(0) FROM information_schema.tables WHERE table_name = 'user' ; ROLLBACK; Executed by issuing: sqitch verify db:pg:test_db Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 10. - When you need to remove changes - Reverting is destructive and the only way to go back is through restoring Reverting Creates file revert/user_table.sql. -- Revert test_postgresql:user_table from pg BEGIN; DROP TABLE "user"; COMMIT; Executed by issuing: sqitch revert db:pg:test_db Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 11. - Overtime changes aren't backward compatible and running sqitch verify will break. - During these times using the --verify switch during deployment tells sqitch to verify what it's deploying, not what has already been deployed. Verifying during deployment Executed by issuing: sqitch deploy --verify db:pg:test_db Verify each migration after deploying. Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 12. The Test::PostgreSQL Module Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 13. - While the name suggests test, it's really a temporary PostgreSQL database Not just for testing! Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 14. - Avoid dbicdump creating my_tmp_table_bkup - Force truth into sqitch DBIC Schema Update Utility • Helps keep sqitch deployments and DBIC schemas in sync • Ensures that developer temporary changes don't make their way into DBIC schemas Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 15. - Creates a new PostgreSQL database - Deploys sqitch database migrations to it - Runs dbicdump to create the DBIC schema packages - This code is going to become familiar dbic_update.pl use App::Sqitch; use App::Sqitch::Command::deploy; use App::Sqitch::Command::verify; use Test::PostgreSQL; my $db = Test::PostgreSQL->new; my $sqitch = App::Sqitch->new( options => { engine => 'pg', }, ); my $deploy = App::Sqitch::Command::deploy->new( sqitch => $sqitch, target => $db->uri, ); $deploy->execute(); say $db->dsn; my $dsn = $db->dsn; $dsn =~ s/^dbi/dbi/i; $dsn =~ s/dbname=/database=/i; system "dbicdump -o dump_directory=./lib MyApp::Schema '$dsn'"; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 16. - calling sqitch from within a script/module was added in 0.996 with a patch from Chris Prather - used to error out on a Moose error Automating Sqitch for Testing Requires App::Sqitch version 0.996 Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 17. - going to create a temporary database - deploy and verify each step in turn - test that reverting each step succeeds - there's no test at the end to make sure the database is back to an empty state Test Sqitch automation • Creates a test database • Runs deploy and verify steps • Reverts changes Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 18. - There is the option of executing the command line via system, however I find this method cleaner, even though it uses more modules up front - Test modules and the App::Sqitch internals Setting up the test use Test::PostgreSQL; use Test::Most; use App::Sqitch; use App::Sqitch::Target; use App::Sqitch::Command::deploy; use App::Sqitch::Command::verify; use App::Sqitch::Command::revert; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 19. - Calling new on Test::PostgreSQL starts the PostgreSQL instance Setting up the database my $db = Test::PostgreSQL->new; my $sqitch = App::Sqitch->new( options => { engine => 'pg', }, ); my $target = App::Sqitch::Target->new( sqitch => $sqitch); my $plan = $target->plan; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 20. - Tell Sqitch that we want to execute using a pg engine - Sqitch classes are a hierarchy, need to build each individual object to proceed Setting up Sqitch my $db = Test::PostgreSQL->new; my $sqitch = App::Sqitch->new( options => { engine => 'pg', }, ); my $target = App::Sqitch::Target->new( sqitch => $sqitch); my $plan = $target->plan; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 21. - Set the Sqitch target and read in the plan file Getting the Sqitch plan my $db = Test::PostgreSQL->new; my $sqitch = App::Sqitch->new( options => { engine => 'pg', }, ); my $target = App::Sqitch::Target->new( sqitch => $sqitch); my $plan = $target->plan; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 22. - plan file contents are not necessarily in order - The $plan iterator is used to get the next step in the plan - Run a deploy on each step via deploy command - to_change will process the plan up to and including the specified change Looping through the plan while ( my $change = $plan->next ) { my $deploy = App::Sqitch::Command::deploy->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name; my $verify = App::Sqitch::Command::verify->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $verify->execute() } 'verify sqitch plan'; push @revert, $change->name; } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 23. - Run a verify on each step via verify command - to_change will process the verify plan up to and including the specified change Looping through the plan while ( my $change = $plan->next ) { my $deploy = App::Sqitch::Command::deploy->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name; my $verify = App::Sqitch::Command::verify->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $verify->execute() } 'verify sqitch plan'; push @revert, $change->name; } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 24. - Store the change to be able to revert it in reverse order later Looping through the plan while ( my $change = $plan->next ) { my $deploy = App::Sqitch::Command::deploy->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name; my $verify = App::Sqitch::Command::verify->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $verify->execute() } 'verify sqitch plan'; push @revert, $change->name; } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 25. - If we try to revert the last change, sqitch will complain that there's nothing further deployed. Looping through the plan pop @revert; while ( my $change_name = pop @revert ) { my $verify = App::Sqitch::Command::revert->new( sqitch => $sqitch, target => $db->uri, to_change => $change_name, no_prompt => 1, ); lives_ok { $verify->execute() } 'revert sqitch plan to ' . $change_name; } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 26. - We've built and verified the entire database structure and now we'll tear it down - Run the revert command on each change Looping through the plan pop @revert; while ( my $change_name = pop @revert ) { my $verify = App::Sqitch::Command::revert->new( sqitch => $sqitch, target => $db->uri, to_change => $change_name, no_prompt => 1, ); lives_ok { $verify->execute() } 'revert sqitch plan to ' . $change_name; } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 27. - highlevel of the module with methods - The skeleton provides methods to be used during your testing: db, dsn, dbh, dbic - Now step into each of the methods Test Module Skeleton package MyApp::Test::PostgreSQL; use strict; use warnings; use App::Sqitch; use Moose; use DBI; use Test::PostgreSQL; use DateTime; use MyApp::Schema; use App::Sqitch::Command::deploy; +-- 6 lines: has db => (----------------------------------------------------------------------------------------- +-- 6 lines: has dsn => (---------------------------------------------------------------------------------------- +-- 15 lines: has dbh => (---------------------------------------------------------------------------------------- +-- 9 lines: has dbic => (--------------------------------------------------------------------------------------- +-- 11 lines: has sqitch => (------------------------------------------------------------------------------------- +-- 7 lines: has fixtures => (----------------------------------------------------------------------------------- +-- 10 lines: has perm_fixtures => (------------------------------------------------------------------------------ +-- 8 lines: sub deploy {---------------------------------------------------------------------------------------- no Moose; __PACKAGE__->meta->make_immutable; 1; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 28. - access to the Test::PostgreSQL object - not really needed during testing directly MyApp::Test::PostgreSQL::db has db => ( is => 'ro', isa => 'Test::PostgreSQL', lazy => 1, default => sub { Test::PostgreSQL->new }, ); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 29. - returns the dsn created by Test::PostgreSQL - simple string that can be used to create additional connections - Create new DBI connections, hand over to applications MyApp::Test::PostgreSQL::dsn has dsn => ( is => 'ro', isa => 'Str', lazy => 1, default => sub { return $_[0]->db->dsn }, ); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 30. - returns a DBI database handle connected to the Test::PostgreSQL instance. - this is a shared connection, transactions might cause issues, if in doubt start a new connection MyApp::Test::PostgreSQL::dbh has dbh => ( is => 'ro', lazy => 1, default => sub { DBI->connect( $_[0]->dsn, undef, undef, { pg_enable_utf8 => 1, RaiseError => 1, AutoCommit => 1, } ) } ); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 31. - returns a DBIC Schema object - uses the Schema object from your application MyApp::Test::PostgreSQL::dbic has dbic => ( is => 'ro', lazy => 1, default => sub { my ($self) = @_; MyApp::Schema->connect({ dbh_maker => sub { $self->dbh }, quote_names => 1, }); } ); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 32. - Data to add to the database for testing - Written by Curtis "Ovid" Poe - While stating that it's Alpha software, we use it a lot Fixtures • DBIx::Class::EasyFixture Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 33. - there's a lot of details here and the packages can get quite large - this example shows the necessities, real world the %definition_for hash is huge - going to break this down and explain what's going on The Fixture Package package MyApp::Test::Fixtures; use Moose; extends 'DBIx::Class::EasyFixture'; use Crypt::Bcrypt::Easy (); my %definition_for = ( basic_user => { new => 'User', using => { user_name => 'tester', password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 ) }, next => [qw(user_entry)], }, user_entry => { new => 'Entry', using => { user_id => 'basic_user', entry => 'This is my entry.', }, }, ); sub get_definition { my ( $self, $name ) = @_; return $definition_for{$name}; } sub all_fixture_names { return keys %definition_for } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 34. - This is the data definition, but more to come We'll come back to this package MyApp::Test::Fixtures; use Moose; extends 'DBIx::Class::EasyFixture'; use Crypt::Bcrypt::Easy (); my %definition_for = ( basic_user => { new => 'User', using => { user_name => 'tester', password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 ) }, next => [qw(user_entry)], }, user_entry => { new => 'Entry', using => { user_id => 'basic_user', entry => 'This is my entry.', }, }, ); sub get_definition { my ( $self, $name ) = @_; return $definition_for{$name}; } sub all_fixture_names { return keys %definition_for } Let's ignore this section for now and return after looking at the basics. Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 35. - DBIx::Class:EasyFixture requires that get_definition and all_fixture_names be overridden. - These are the simplest definitions and can be reused Required overrides package MyApp::Fixtures; use Moose; extends 'DBIx::Class::EasyFixture'; use Crypt::Bcrypt::Easy (); my %definition_for = ( basic_user => { new => 'User', using => { user_name => 'tester', password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 ) }, next => [qw(user_entry)], }, user_entry => { new => 'Entry', using => { user_id => 'basic_user', entry => 'This is my entry.', }, }, ); sub get_definition { my ( $self, $name ) = @_; return $definition_for{$name}; } sub all_fixture_names { return keys %definition_for } Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 36. - basic_user is a unique identifier - new is the result set full package name is MyApp::Schema::Result::User - using is the record data - able to mix in function calls like password - next and requires can be used to specify fixture dependencies - STRINGREF is a reference to an existing Data definition ... my %definition_for = ( basic_user => { new => 'User', using => { user_name => 'tester', password => Crypt::Bcrypt::Easy->crypt( text => 'tester', cost => 10 ) }, next => [qw(user_entry)], }, user_entry => { new => 'Entry', using => { user_id => 'basic_user', entry => 'This is my entry.', }, }, ); ... Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 37. - Access to the fixtures object - Fixtures by default are written in one transaction MyApp::Test::PostgreSQL::fixtures has fixtures => ( is => 'ro', lazy => 1, default => sub { MyApp::Test::Fixtures->new( { schema => $_[0]->dbic } ) }, ); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 38. - Access to the fixtures object - Disable transactions so that other sessions can access the data MyApp::Test::PostgreSQL::perm_fixtures has perm_fixtures => ( is => 'ro', lazy => 1, default => sub { MyApp::Test::Fixtures->new( { schema => $_[0]->dbic, no_transactions => 1, } ) }, ); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 39. - At this point you have a populated database - New connections can access the database via $dsn - diag $dsn is useful for connecting with an external client - full access to the MyApp::Test::PostgreSQL methods for access to dbh, and dbic Actually writing tests use MyApp::Test::PostgreSQL; use MyApp::Test::Fixtures; use Test::Most; my $db = MyApp::Test::PostgreSQL->new; my $dbic = $db->dbic; my $dsn = $db->dsn; $dsn =~ s/^dbi/dbi/i; diag $dsn; lives_ok { $db->deploy } 'database set up'; $db->perm_fixtures->load('basic_user'); # Add all your test methods here $db->perm_fixtures->unload; done_testing; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 40. - t/lib required as that's where the MyApp::Test modules live Running tests prove -lv -I t/lib t/simple.t t/simple.t .. # dbi:Pg:dbname=test;host=127.0.0.1;port=15432;user=postgres Adding registry tables to db:postgresql://postgres@127.0.0.1:15432/test Deploying changes to db:postgresql://postgres@127.0.0.1:15432/test + user_table ... ok + entry_table .. ok ok 1 - database set up 1..1 Pg refused to die gracefully; killing it violently. Pg really didn't die.. WTF? ok All tests successful. Files=1, Tests=1, 20 wallclock secs ( 0.03 usr 0.02 sys + 2.53 cusr 1.31 csys = 3.89 CPU) Result: PASS Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 41. - Yeah, these error messages are interesting - non-impacting, might have something to do with fixtures WTF? prove -lv -I t/lib t/simple.t t/simple.t .. # dbi:Pg:dbname=test;host=127.0.0.1;port=15432;user=postgres Adding registry tables to db:postgresql://postgres@127.0.0.1:15432/test Deploying changes to db:postgresql://postgres@127.0.0.1:15432/test + user_table ... ok + entry_table .. ok ok 1 - database set up 1..1 Pg refused to die gracefully; killing it violently. Pg really didn't die.. WTF? ok All tests successful. Files=1, Tests=1, 20 wallclock secs ( 0.03 usr 0.02 sys + 2.53 cusr 1.31 csys = 3.89 CPU) Result: PASS Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 42. - Written by Curtis "Ovid" Poe - Originally written by Curtis "Ovid" Poe, and now maintained by Dave Rolsky - Haven't used Test::mongod though it's on my list of modules to try and tests to migrate, written by co-worker Jesse Shy More Reading • DBIx::Class::EasyFixture::Tutorial - It's complicated • Test::Class::Moose - Serious testing for serious Perl • Test::mongod - run a temporary instance of MongoDB by Jesse Shy Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 43. References • Test::PostgreSQL • Reply • App::Sqitch • DBIx::Class::EasyFixture Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 44. MoreTesting with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 45. Updating DBIC Schemas #!/bin/env perl use v5.20; use autodie ':all'; use App::Sqitch; use App::Sqitch::Command::deploy; use App::Sqitch::Command::verify; use Test::PostgreSQL; my $db = Test::PostgreSQL->new; my $sqitch = App::Sqitch->new( options => { engine => 'pg', }, ); my $deploy = App::Sqitch::Command::deploy->new( sqitch => $sqitch, target => $db->uri, ); $deploy->execute(); say $db->dsn; my $dsn = $db->dsn; $dsn =~ s/^dbi/dbi/i; $dsn =~ s/dbname=/database=/i; system "dbicdump -o dump_directory=./lib MyApp::Schema '$dsn'"; Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti
  • 46. sqitch.t use Test::PostgreSQL; use Test::Most; use App::Sqitch; use App::Sqitch::Target; use App::Sqitch::Command::deploy; use App::Sqitch::Command::verify; use App::Sqitch::Command::revert; bail_on_fail; my $db = Test::PostgreSQL->new; my $sqitch = App::Sqitch->new( options => { engine => 'pg', }, ); my $target = App::Sqitch::Target->new( sqitch => $sqitch); my $plan = $target->plan; my ( @revert ); while ( my $change = $plan->next ) { my $deploy = App::Sqitch::Command::deploy->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $deploy->execute() } 'deploy sqitch plan to ' . $change->name; my $verify = App::Sqitch::Command::verify->new( sqitch => $sqitch, target => $db->uri, to_change => $change->name, ); lives_ok { $verify->execute() } 'verify sqitch plan'; push @revert, $change->name; } pop @revert; while ( my $change_name = pop @revert ) { my $verify = App::Sqitch::Command::revert->new( sqitch => $sqitch, target => $db->uri, to_change => $change_name, no_prompt => 1, ); lives_ok { $verify->execute() } 'revert sqitch plan to ' . $change_name; } done_testing(); Testing with Postgresql // Toronto Perl Mongers // Shawn Sorichetti