pgTAP Best Practices
         David E. Wheeler

         Kineticode, Inc.
     PostgreSQL Experts, Inc.

 PostgreSQL Confe...
OMG TAP WTF?
Test Anything Protocol (TAP) is a general purpose
format for transmitting the result of test
programs to a th...
What is TAP?
What is TAP?
What does that mean in practice?
What is TAP?
What does that mean in practice?

Test output easy to interpret
What is TAP?
What does that mean in practice?

Test output easy to interpret

  By humans
What is TAP?
What does that mean in practice?

Test output easy to interpret

  By humans

  By computers
What is TAP?
What does that mean in practice?

Test output easy to interpret

  By humans

  By computers

  By aliens
What is TAP?
What does that mean in practice?

Test output easy to interpret

  By humans

  By computers

  By aliens

  ...
TAP Output
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
not o...
TAP Output
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
ok 4 ...
TAP Output
% perl -Ilib t/try.t
1..5
ok 1 - use FSA::Rules;
ok 2 - Create FSA::Rules object
ok 3 - Start the machine
ok 4 ...
Writing Tests
Writing Tests

use Test::More tests => 5;

use_ok 'FSA::Rules';
ok my $r = FSA::Rules->new,
  'Create FSA::Rules object';
...
Writing Tests

use Test::More tests => 5;

use_ok 'FSA::Rules';
ok my $r = FSA::Rules->new,
  'Create FSA::Rules object';
...
Writing Tests

use Test::More tests => 5;

use_ok 'FSA::Rules';
ok my $r = FSA::Rules->new,
  'Create FSA::Rules object';
...
Writing Tests

use Test::More tests => 5;

use_ok 'FSA::Rules';
ok my $r = FSA::Rules->new,
  'Create FSA::Rules object';
...
Writing Tests

use Test::More tests => 5;

use_ok 'FSA::Rules';
ok my $r = FSA::Rules->new,
  'Create FSA::Rules object';
...
Writing Tests

use Test::More tests => 5;

use_ok 'FSA::Rules';
ok my $r = FSA::Rules->new,
  'Create FSA::Rules object';
...
pgTAP
pgTAP
Includes most Test::More functions
pgTAP
Includes most Test::More functions

  ok() — Boolean
pgTAP
Includes most Test::More functions

  ok() — Boolean

  is() — Value comparison
pgTAP
Includes most Test::More functions

  ok() — Boolean

  is() — Value comparison

  isnt() — NOT is()
pgTAP
Includes most Test::More functions

  ok() — Boolean

  is() — Value comparison

  isnt() — NOT is()

  cmp_ok() — C...
pgTAP
Includes most Test::More functions

  ok() — Boolean

  is() — Value comparison

  isnt() — NOT is()

  cmp_ok() — C...
pgTAP
Includes most Test::More functions

  ok() — Boolean

  is() — Value comparison

  isnt() — NOT is()

  cmp_ok() — C...
pgTAP
pgTAP
Includes Test controls
pgTAP
Includes Test controls

  plan() — How many tests?
pgTAP
Includes Test controls

  plan() — How many tests?

  no_plan() — Unknown number of tests
pgTAP
Includes Test controls

  plan() — How many tests?

  no_plan() — Unknown number of tests

  diag() — Diagnostic out...
pgTAP
Includes Test controls

  plan() — How many tests?

  no_plan() — Unknown number of tests

  diag() — Diagnostic out...
Follow Along!
http:/
     /pgtap.projects.postgresql.org/
Installing pgTAP
Installing pgTAP

% tar jxf pgtap-0.22.tar.bz2
Installing pgTAP

% tar jxf pgtap-0.22.tar.bz2
% cd pgtap-0.22
Installing pgTAP

% tar jxf pgtap-0.22.tar.bz2
% cd pgtap-0.22
% make TAPSCHEMA=tap SE_PGXS=1
                        U
Installing pgTAP

% tar jxf pgtap-0.22.tar.bz2
% cd pgtap-0.22
% make TAPSCHEMA=tap SE_PGXS=1
                        U
  ...
Installing pgTAP

% tar jxf pgtap-0.22.tar.bz2
% cd pgtap-0.22
% make TAPSCHEMA=tap
                       If in contrib…
Installing pgTAP

%   tar jxf pgtap-0.22.tar.bz2
%   cd pgtap-0.22
%   make TAPSCHEMA=tap
%   sudo make install
Installing pgTAP

%   tar jxf pgtap-0.22.tar.bz2
%   cd pgtap-0.22
%   make TAPSCHEMA=tap
%   sudo make install
%   make i...
Installing pgTAP

%   tar jxf pgtap-0.22.tar.bz2
%   cd pgtap-0.22
%   make TAPSCHEMA=tap
%   sudo make install
%   make i...
Installing pgTAP

%   tar jxf pgtap-0.22.tar.bz2
%   cd pgtap-0.22
%   make TAPSCHEMA=tap
%   sudo make install
%   make i...
pgTAP Basics
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;


-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELECT ok( true, 'Truth should be tr...
pgTAP Basics

BEGIN;
SET search_path TO tap, public;

-- Plan the tests.
SELECT plan(1);
--SELECT * FROM no_plan();

SELEC...
Running Tests
Running Tests
% pg_prove -v -d try try.sql
try.sql .. psql:try.sql:5: ERROR: function plan(integer) does
not exist
LINE 1:...
Running Tests
% pg_prove -v -d try try.sql
try.sql .. psql:try.sql:5: ERROR: function plan(integer) does
not exist
LINE 1:...
Running Tests
%
Running Tests
%export PGOPTIONS=--search_path=tap,public
%
Running Tests
%export PGOPTIONS=--search_path=tap,public
%pg_prove -v -d try try.sql
try.sql ..
1..1
ok 1 - Truth should b...
Running Tests
%export PGOPTIONS=--search_path=tap,public
%pg_prove -v -d try try.sql
try.sql ..
1..1
ok 1 - Truth should b...
Failure
Failure

BEGIN;

SELECT plan(2);
SELECT ok( 1 + 1 = 2 );
SELECT ok( 2 + 2 = 5 );

SELECT * FROM finish();
ROLLBACK;
Failing Tests
Failing Tests

%
Failing Tests

%pg_prove -v -d try fail.sql
fail.sql ..
1..2
ok 1
not ok 2
# Failed test 2
# Looks like you failed 1 test ...
Failing Tests

%pg_prove -v -d try fail.sql
fail.sql ..
1..2
ok 1
not ok 2
# Failed test 2
# Looks like you failed 1 test ...
Failing Tests

%pg_prove -v -d try fail.sql
fail.sql ..
1..2
ok 1
not ok 2
# Failed test 2
# Looks like you failed 1 test ...
Failing Tests

%pg_prove -v -d try fail.sql
fail.sql ..
1..2
ok 1
not ok 2
# Failed test 2
# Looks like you failed 1 test ...
Failing Tests

%pg_prove -v -d try fail.sql
fail.sql ..
1..2
ok 1
not ok 2
# Failed test 2
# Looks like you failed 1 test ...
Scalar Testing
Scalar Testing
Where to start testing?
Scalar Testing
Where to start testing?

Start with one unit of code
Scalar Testing
Where to start testing?

Start with one unit of code

Maybe a custom data type
Scalar Testing
Where to start testing?

Start with one unit of code

Maybe a custom data type

Obvious candidate for scala...
Scalar Testing
Where to start testing?

Start with one unit of code

Maybe a custom data type

Obvious candidate for scala...
Testing hstore
Testing hstore

BEGIN;

SELECT plan(2);
SELECT ok( 'k => 1'::hstore IS NOT NULL );
SELECT ok(
   pg_typeof('k' => '2') = '...
Testing hstore
Testing hstore

%
Testing hstore

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..2
ok 1
ok 2
ok
All tests successful.
Testing hstore

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..2
ok 1
ok 2
ok
All tests successful.

                    ...
Describe Yourself
Describe Yourself

SELECT plan(2);
SELECT ok(
   'k => 1'::hstore IS NOT NULL,
   'hstore should work'
);
SELECT ok(
   pg...
Describe Yourself
Describe Yourself

%
Describe Yourself

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..2
ok 1 - hstore should work
ok 2 - => should create hst...
Simplify, Simplify

SELECT plan(2);
SELECT ok(
   'k => 1'::hstore IS NOT NULL,
   'hstore should work'
);
SELECT ok(
   p...
Simplify, Simplify

SELECT plan(2);
SELECT ok(
   'k => 1'::hstore IS NOT NULL,
   'hstore should work'
);
SELECT isa_ok(
...
Simplify, Simplify
Simplify, Simplify

%
Simplify, Simplify

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..2
ok 1 - hstore should work
ok 2 - => return value isa...
Test the Manual
Test the Manual
SELECT plan(6);

SELECT   ok(   'a=>x, b=>y'::hstore -> 'a' = 'x', 'op ->' );
SELECT   ok(   'a=>1'::hstor...
Test the Manual
Test the Manual

%
Test the Manual

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
ok 4 - op <@
not ...
Test the Manual

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
                 ...
What is() It?
SELECT plan(6);

SELECT   ok'a=>x, b=>y'::hstore -> 'a' 'x', 'op ->' );
          (                         ...
What is() It?
SELECT plan(6);

SELECT   is 'a=>x, b=>y'::hstore -> 'a' 'x', ,'op ->' );
           (
SELECT   ok( 'a=>1'::...
%
%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
ok 4 - op <@
not ok 5 - akeys()
# ...
%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
ok 4 - op <@
not ok 5 - akeys()
# ...
%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
                        There it i...
What is() It?
SELECT plan(6);

SELECT   is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' );
SELECT   ok( 'a=>1'::hstore ? 'a'...
What is() It?
SELECT plan(6);

SELECT   is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' );
SELECT   ok( 'a=>1'::hstore ? 'a'...
What is() It?
SELECT plan(6);

SELECT   is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' );
SELECT   ok( 'a=>1'::hstore ? 'a'...
What is() It?
SELECT plan(6);

SELECT   is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' );
SELECT   ok( 'a=>1'::hstore ? 'a'...
What is() It?
What is() It?

%
What is() It?

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
ok 4 - op <@
ok 5 -...
What is() It?

%pg_prove -v -d try hstore.sql
hstore.sql ..
1..6
ok 1 - op ->
ok 2 - op ?
ok 3 - op @>
                   ...
Repetition
Repetition
Want to test lots of values
Repetition
Want to test lots of values

Try to trick code with edge cases
Repetition
Want to test lots of values

Try to trick code with edge cases

Writing same tests with different values
Repetition
Want to test lots of values

Try to trick code with edge cases

Writing same tests with different values

Could...
Repetition
Want to test lots of values

Try to trick code with edge cases

Writing same tests with different values

Could...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,    -- val -> arrow_...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,    -- val -> arrow_...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,    -- val -> arrow_...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SET client_min_messages = warning;
CREATE TEMPORARY TABLE hs_tests (
   val hstore,
   arrow_rop text,
   arrow_val text,
...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
SELECT plan(COUNT(*)::int * 4) FROM hs_tests;

SELECT is(
   val -> arrow_rop,
   arrow_val,
   quote_literal(val) || ' ? ...
Repetition
Repetition
%
Repetition
%pg_prove -v -d try hstore.sql
hstore.sql ..
1..8
ok 1 - '"a"=>"1", "b"=>"2"' ? '1'
ok 2 - '"a"=>"1"' ? '1'
ok ...
Add Tests
-- Insert test values.
INSERT INTO hs_tests VALUES
('a=>1,b=>2', 'a', '1', 'a', '{a,b}', '{1,2}'),
('a=>1',     ...
Add Tests
-- Insert test values.
INSERT INTO hs_tests VALUES
('a=>1,b=>2', 'a', '1', 'a', '{a,b}', '{1,2}'),
('a=>1',     ...
More Repetition
More Repetition

%
More Repetition

%pg_prove -d try hstore.sql
hstore.sql ..
All tests successful.
Files=1, Tests=20, 0 wallclock secs
( 0.0...
More Repetition

%pg_prove -d try hstore.sql
hstore.sql ..
All tests successful.
Files=1, Tests=20, 0 wallclock secs
( 0.0...
More Repetition

%pg_prove -d try hstore.sql
hstore.sql ..
All tests successful.
Files=1, Tests=20, 0 wallclock secs
( 0.0...
Skipping Tests
Skipping Tests
Sometimes need to skip tests
Skipping Tests
Sometimes need to skip tests

  Platform dependencies
Skipping Tests
Sometimes need to skip tests

  Platform dependencies

  Collation dependencies
Skipping Tests
Sometimes need to skip tests

  Platform dependencies

  Collation dependencies

  Version dependencies
Skipping Tests
Sometimes need to skip tests

  Platform dependencies

  Collation dependencies

  Version dependencies

Us...
Skipping Tests
Skipping Tests
SELECT CASE os_name() WHEN 'darwin' THEN
  cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o')
ELSE
  skip('Collati...
Skipping Tests
SELECT CASE os_name() WHEN 'darwin' THEN
  cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o')
ELSE
  skip('Collati...
Skipping Tests
SELECT CASE os_name() WHEN 'darwin' THEN
  cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o')
ELSE
  skip('Collati...
Skipping Tests
SELECT CASE os_name() WHEN 'darwin' THEN
  cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o')
ELSE
  skip('Collati...
Skipping Tests
SELECT CASE os_name() WHEN 'darwin' THEN
  cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o')
ELSE
  skip('Collati...
Skipping Tests
Skipping Tests

%
Skipping Tests

%pg_prove -v -d try collation.sql
collation.sql ..
1..1
ok 1 - ø > o
ok
All tests successful.
Files=1, Tes...
Skipping Tests

%pg_prove -v -d try collation.sql
collation.sql ..
1..1
ok 1 - ø > o
ok
All tests successful.
Files=1, Tes...
Skipping Tests

%pg_prove -v -d try collation.sql
collation.sql ..
1..1
ok 1 - ø > o
ok
All tests successful.
Files=1, Tes...
Skipping Tests
Skipping Tests

%
Skipping Tests

%pg_prove -v -d try collation.sql
collation.sql ..
1..1
ok 1 - SKIP: Collation-specific test
ok
All tests s...
Skipping Tests

%pg_prove -v -d try collation.sql
collation.sql ..
1..1
ok 1 - SKIP: Collation-specific test
ok
All tests s...
Skipping Tests

%pg_prove -v -d try collation.sql
collation.sql ..
1..1
ok 1 - SKIP: Collation-specific test
ok
All tests s...
Skip More
Skip More
SELECT CASE os_name() WHEN 'darwin' THEN
  array_to_string( ARRAY[
      cmp_ok( 'Bjørn'::text, '>', 'Bjorn', 'ø...
Skip More
Skip More

%
Skip More

%pg_prove -v -d try collation.sql
collation.sql ..
1..4
ok 1 - ø > o
ok 2 - ı > i
ok 3 - é > e
ok 4 - ä > a
ok
...
Skip More

%pg_prove -v -d try collation.sql
collation.sql ..
1..4
ok 1 - ø > o
ok 2 - ı > i
ok 3 - é > e
ok 4 - ä > a
ok
...
Skip More
Skip More

%
Skip More

%pg_prove -v -d try collation.sql
collation.sql ..
1..4
ok 1 - SKIP: Collation-specific test
ok 2 - SKIP: Collat...
Skip More

%pg_prove -v -d try collation.sql
collation.sql ..
1..4
ok 1 - SKIP: Collation-specific test
ok 2 - SKIP: Collat...
Todo Tests
Todo Tests
Sometimes need to ignore failures
Todo Tests
Sometimes need to ignore failures

  Features not implemented
Todo Tests
Sometimes need to ignore failures

  Features not implemented

  Unfixed regression
Todo Tests
Sometimes need to ignore failures

  Features not implemented

  Unfixed regression

  Version dependences
Todo Tests
Sometimes need to ignore failures

  Features not implemented

  Unfixed regression

  Version dependences

Use ...
Todo Tests
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
Todo Tests
%
Todo Tests
%pg_prove -v -d try text.sql
text.sql ..
ok 1 - text is text isa text
ok 2 - $$ is text isa text
not ok 3 - sho...
Todo Tests
%pg_prove -v -d try text.sql
text.sql ..                            Will get
ok 1 - text is text isa text
ok 2 ...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
Todo Tests
%
Todo Tests
%pg_prove -v -d try text.sql
text.sql ..
1..4
ok 1 - text is text isa text
ok 2 - $$ is text isa text
not ok 3 ...
Todo Tests
%pg_prove -v -d try text.sql
text.sql ..
1..4
ok 1 - text is text isa text
ok 2 - $$ is text isa text
not ok 3 ...
Todo Tests
%pg_prove -v -d try text.sql
text.sql ..
1..4
ok 1 - text is text isa text
ok 2 - $$ is text isa text
not ok 3 ...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
SELECT plan(4);

SELECT isa_ok('foo'::text, 'text', 'text is text');
SELECT isa_ok($$foo$$::text, 'text', '$$ i...
Todo Tests
Todo Tests
%
Todo Tests
%pg_prove -v -d try text.sql
text.sql ..
1..4
ok 1 - text is text isa text
ok 2 - $$ is text isa text
not ok 3 ...
Other Goodies
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
SELECT * FROM no_plan();

SELECT matches( :zip_code, '^[[:digit:]]{5}$' );
SELECT alike( :country, 'United %...
Other Goodies
Other Goodies
%
Other Goodies
%pg_prove -v -d try goodies.sql
goodies.sql ..
ok 1
ok 2
ok 3 - threw 42883
ok 4 - threw function lower(nume...
Other Goodies
%pg_prove -v -d try goodies.sql
goodies.sql ..
ok 1
ok 2
ok 3 - threw 42883
ok 4 - threw function lower(nume...
Other Goodies
%pg_prove -v -d try goodies.sql
goodies.sql ..
ok 1
ok 2
ok 3 - threw 42883
ok 4 - threw function lower(nume...
Other Goodies
%pg_prove -v -d try goodies.sql
goodies.sql ..
ok 1
ok 2
ok 3 - threw 42883
ok 4 - threw function lower(nume...
Other Goodies
%pg_prove -v -d try goodies.sql
goodies.sql ..
ok 1
ok 2
ok 3 - threw 42883
ok 4 - threw function lower(nume...
Pursuing your Query
Pursuing your Query
Several functions execute queries
Pursuing your Query
Several functions execute queries

Seen throws_ok(), lives_ok(), performs_ok()
Pursuing your Query
Several functions execute queries

Seen throws_ok(), lives_ok(), performs_ok()

Take SQL statement arg...
Pursuing your Query
Several functions execute queries

Seen throws_ok(), lives_ok(), performs_ok()

Take SQL statement arg...
Pursuing your Query
Several functions execute queries

Seen throws_ok(), lives_ok(), performs_ok()

Take SQL statement arg...
Pursuing your Query
Several functions execute queries

Seen throws_ok(), lives_ok(), performs_ok()

Take SQL statement arg...
Pursuing your Query
Pursuing your Query
PREPARE new_user AS
INSERT INTO users (nick, pass, name)
VALUES ('theory', 's3kr1t', 'David Wheeler');...
Pursuing your Query
PREPARE new_user AS
INSERT INTO users (nick, pass, name)
VALUES ('theory', 's3kr1t', 'David Wheeler');...
Pursuing your Query
PREPARE new_user AS
INSERT INTO users (nick, pass, name)
VALUES ('theory', 's3kr1t', 'David Wheeler');...
Pursuing your Query
PREPARE new_user AS
INSERT INTO users (nick, pass, name)
VALUES ('theory', 's3kr1t', 'David Wheeler');...
Testing Relations
Testing Relations
Not everything is a scalar
Testing Relations
Not everything is a scalar

It’s a RELATIONAL database, after all
Testing Relations
Not everything is a scalar

It’s a RELATIONAL database, after all

Only so much coercion to scalars to do
Testing Relations
Not everything is a scalar

It’s a RELATIONAL database, after all

Only so much coercion to scalars to d...
Testing Relations
Not everything is a scalar

It’s a RELATIONAL database, after all

Only so much coercion to scalars to d...
Testing Relations
Not everything is a scalar

It’s a RELATIONAL database, after all

Only so much coercion to scalars to d...
Testing Relations
Not everything is a scalar

It’s a RELATIONAL database, after all

Only so much coercion to scalars to d...
results_eq()
results_eq()
Tests query results
results_eq()
Tests query results

Row-by-row comparison
results_eq()
Tests query results

Row-by-row comparison

In order
results_eq()
Tests query results

Row-by-row comparison

In order

Test query and expected query may be:
results_eq()
Tests query results

Row-by-row comparison

In order

Test query and expected query may be:

  SQL statements
results_eq()
Tests query results

Row-by-row comparison

In order

Test query and expected query may be:

  SQL statements...
results_eq()
Tests query results

Row-by-row comparison

In order

Test query and expected query may be:

  SQL statements...
Testing Results
Testing Results
Example: active_users()
Testing Results
Example: active_users()

Returns set of active users
Testing Results
Example: active_users()

Returns set of active users

Test the function
Testing Results
Example: active_users()

Returns set of active users

Test the function

Compare results
results_eq() Arguments
results_eq() Arguments
SELECT results_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active ORDER BY...
results_eq() Arguments
SELECT results_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active ORDER BY...
results_eq() Arguments
SELECT results_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active ORDER BY...
results_eq() Arguments
SELECT results_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active ORDER BY...
results_eq() Arguments
SELECT results_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active ORDER BY...
results_eq() Arguments
results_eq() Arguments
PREPARE users_test AS SELECT * FROM active_users();
PREPARE users_expect AS
 SELECT * FROM users WH...
results_eq() Arguments
PREPARE users_test AS SELECT * FROM active_users();
PREPARE users_expect AS
 SELECT * FROM users WH...
results_eq() Arguments
PREPARE users_test AS SELECT * FROM active_users();
PREPARE users_expect AS
 SELECT * FROM users WH...
results_eq() Arguments
PREPARE users_test AS SELECT * FROM active_users();
PREPARE users_expect AS
 SELECT * FROM users WH...
results_eq() Arguments
PREPARE users_test AS SELECT * FROM active_users();
PREPARE users_expect AS
 SELECT * FROM users WH...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
PREPARE get_users_test(boolean) AS
 SELECT * FROM get_users($1);

PREPARE get_users_expect(boolean) AS
 SELECT * FROM user...
results_eq() Single
 Column & Array
results_eq() Single
          Column & Array
SELECT results_eq(
   'SELECT * FROM active_user_nicks()',
   ARRAY[ 'anna', ...
results_eq() Single
          Column & Array
SELECT results_eq(
   'SELECT * FROM active_user_nicks()',
   ARRAY[ 'anna', ...
results_eq() Single
          Column & Array
SELECT results_eq(
   'SELECT * FROM active_user_nicks()',
   ARRAY[ 'anna', ...
Testing Results
Testing Results
%
Testing Results
%pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() should return active users
ok 2...
Differing Rows
     Diagnostics
%
Differing Rows
               Diagnostics
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() shou...
Differing Rows
               Diagnostics
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() shou...
Differing Columns
       Diagnostics
%
Differing Columns
             Diagnostics
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() ret...
Differing Columns
             Diagnostics
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() ret...
Missing Row Diagnostics
%
Missing Row Diagnostics
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() return active users
no...
Missing Row Diagnostics
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() return active users
no...
Diagnostics for Differing
          Data Types
%
Diagnostics for Differing
       Data Types
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() re...
Diagnostics for Differing
       Data Types
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() re...
Diagnostics for Differing
       Data Types
% pg_prove -v -d try results_eq.sql
results_eq.sql ..
ok 1 - active_users() re...
Testing Sets
Testing Sets
When order does not matter
Testing Sets
When order does not matter

When duplicate tuples do not matter
Testing Sets
When order does not matter

When duplicate tuples do not matter

Use queries
Testing Sets
When order does not matter

When duplicate tuples do not matter

Use queries

Or prepared statement names
Testing Bags
Testing Bags
When order does not matter
Testing Bags
When order does not matter

Duplicates matter
Testing Bags
When order does not matter

Duplicates matter

Use queries
Testing Bags
When order does not matter

Duplicates matter

Use queries

Or prepared statement names
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
SELECT set_eq(
   'SELECT * FROM active_users()',
   'SELECT * FROM users WHERE active',
   'active_users() should return ...
Differing Rows
     Diagnostics
%
Differing Rows
               Diagnostics
% pg_prove -v -d try set_eq.sql
set_eq.sql ..
ok 1 - active_users() return activ...
Differing Rows
               Diagnostics
% pg_prove -v -d try set_eq.sql
set_eq.sql ..
ok 1 - active_users() return activ...
Diagnostics for Differing
      Data Types
%
Diagnostics for Differing
       Data Types
%pg_prove -v -d try set_eq.sql
set_eq.sql ..
ok 1 - active_users() return acti...
Diagnostics for Differing
       Data Types
%pg_prove -v -d try set_eq.sql
set_eq.sql ..
ok 1 - active_users() return acti...
Diagnostics for Different
  Numbers of Columns
%
Diagnostics for Different
   Numbers of Columns
%pg_prove -v -d try set_eq.sql
set_eq.sql ..
ok 1 - active_users() return ...
Diagnostics for Different
   Numbers of Columns
%pg_prove -v -d try set_eq.sql
set_eq.sql ..
ok 1 - active_users() return ...
Structural Testing
Structural Testing
Validate presence/absence of objects
Structural Testing
Validate presence/absence of objects

*_are()
Structural Testing
Validate presence/absence of objects

*_are()

Specify complete lists of objects
Structural Testing
Validate presence/absence of objects

*_are()

Specify complete lists of objects

Useful failure diagno...
SELECT tablespaces_are(
   ARRAY[ 'dbspace', 'indexspace' ]
);
SELECT tablespaces_are(
   ARRAY[ 'dbspace', 'indexspace' ]
);
SELECT schemas_are(
   ARRAY[ 'public', 'contrib', 'biz' ]
...
SELECT tablespaces_are(
   ARRAY[ 'dbspace', 'indexspace' ]
);
SELECT schemas_are(
   ARRAY[ 'public', 'contrib', 'biz' ]
...
SELECT tablespaces_are(
   ARRAY[ 'dbspace', 'indexspace' ]
);
SELECT schemas_are(
   ARRAY[ 'public', 'contrib', 'biz' ]
...
SELECT tablespaces_are(
   ARRAY[ 'dbspace', 'indexspace' ]
);
SELECT schemas_are(
   ARRAY[ 'public', 'contrib', 'biz' ]
...
SELECT indexes_are(
   'biz', 'users',
   ARRAY[ 'users_pkey' ]
);
SELECT indexes_are(
   'biz', 'users',
   ARRAY[ 'users_pkey' ]
);

SELECT functions_are(
   'biz',
   ARRAY[ 'get_users',...
SELECT indexes_are(
   'biz', 'users',
   ARRAY[ 'users_pkey' ]
);

SELECT functions_are(
   'biz',
   ARRAY[ 'get_users',...
SELECT indexes_are(
   'biz', 'users',
   ARRAY[ 'users_pkey' ]
);

SELECT functions_are(
   'biz',
   ARRAY[ 'get_users',...
Structural Testing
Structural Testing
SELECT languages_are(
   ARRAY[ 'plpgsql', 'plperlu', 'plperl' ]
);
Structural Testing
SELECT languages_are(
   ARRAY[ 'plpgsql', 'plperlu', 'plperl' ]
);
SELECT opclasses_are(
   'biz',
   ...
Structural Testing
SELECT languages_are(
   ARRAY[ 'plpgsql', 'plperlu', 'plperl' ]
);
SELECT opclasses_are(
   'biz',
   ...
%
%pg_prove -v -d try schema.sql
schema.sql ..
ok 1 - There should be the correct schemas
not ok 2 - Schema biz should have ...
%pg_prove -v -d try schema.sql
schema.sql ..
ok 1 - There should be the correct schemas
not ok 2 - Schema biz should have ...
Schema Testing
Schema Testing
Validate presence of objects
Schema Testing
Validate presence of objects

Validate object interfaces
Schema Testing
Validate presence of objects

Validate object interfaces

Prevent others from changing schema
Schema Testing
Validate presence of objects

Validate object interfaces

Prevent others from changing schema

Maintain a c...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
BEGIN;
SET search_path TO public, tap;
SELECT plan(13);

SELECT has_table( 'users' );
SELECT has_pk( 'users' );

SELECT   ...
SELECT   has_tablespace( 'indexspace', '/data/idxs' );
SELECT   has_schema( 'biz' );
SELECT   has_view( 'biz', 'list_users...
Function Testing
   Functions
Function Testing
                 Functions
SELECT   function_lang_is( 'biz', 'get_user', 'sql' );
SELECT   function_retur...
Utilities
Utilities
SELECT CASE WHEN pgtap_version() < 0.17
  THEN skip('No sequence assertions before pgTAP 0.17')
  ELSE has_seque...
Utilities
SELECT CASE WHEN pgtap_version() < 0.17
  THEN skip('No sequence assertions before pgTAP 0.17')
  ELSE has_seque...
Utilities
SELECT CASE WHEN pgtap_version() < 0.17
  THEN skip('No sequence assertions before pgTAP 0.17')
  ELSE has_seque...
Other Features and Topics
Other Features and Topics
  xUnit-Style testing
Other Features and Topics
  xUnit-Style testing

  Test-Driven development
Other Features and Topics
  xUnit-Style testing

  Test-Driven development

  Integration with Perl unit tests
Other Features and Topics
  xUnit-Style testing

  Test-Driven development

  Integration with Perl unit tests

  Integrat...
Other Features and Topics
  xUnit-Style testing

  Test-Driven development

  Integration with Perl unit tests

  Integrat...
Other Features and Topics
  xUnit-Style testing

  Test-Driven development

  Integration with Perl unit tests

  Integrat...
Other Features and Topics
  xUnit-Style testing

  Test-Driven development

  Integration with Perl unit tests

  Integrat...
Other Features and Topics
  xUnit-Style testing

  Test-Driven development

  Integration with Perl unit tests

  Integrat...
Thank You
pgTAP Best Practices
         David E. Wheeler

         Kineticode, Inc.
     PostgreSQL Experts, Inc.

 Postgr...
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
PgTAP Best Practices
Upcoming SlideShare
Loading in …5
×

PgTAP Best Practices

4,200
-1

Published on

So you've got testing religion, but the question now is, how do you test your database?

This tutorial introduces pgTAP, a comprehensive, easy-to-use test suite for PostgreSQL. We'll work from getting and installing pgTAP, to writing a simple test, to running the test and integrating it into your test environment. And then we really get into the fun stuff:

Testing scalar values
Testing error conditions and performance regressions
Testing database schemas, including tables, columns, constraints, indexes, triggers, etc.
Testing result sets
Testing procedures

Testing may sound like a dry topic, but my examples aren't! Come join the fun!

Published in: Technology, Business
0 Comments
9 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
4,200
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
121
Comments
0
Likes
9
Embeds 0
No embeds

No notes for slide
  • PgTAP Best Practices

    1. 1. pgTAP Best Practices David E. Wheeler Kineticode, Inc. PostgreSQL Experts, Inc. PostgreSQL Conference West 2009
    2. 2. OMG TAP WTF? Test Anything Protocol (TAP) is a general purpose format for transmitting the result of test programs to a thing which interprets and takes action on those results. Though it is language agnostic, it is primarily used by Perl modules. —Wikipedia
    3. 3. What is TAP?
    4. 4. What is TAP? What does that mean in practice?
    5. 5. What is TAP? What does that mean in practice? Test output easy to interpret
    6. 6. What is TAP? What does that mean in practice? Test output easy to interpret By humans
    7. 7. What is TAP? What does that mean in practice? Test output easy to interpret By humans By computers
    8. 8. What is TAP? What does that mean in practice? Test output easy to interpret By humans By computers By aliens
    9. 9. What is TAP? What does that mean in practice? Test output easy to interpret By humans By computers By aliens By gum!
    10. 10. TAP Output
    11. 11. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    12. 12. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    13. 13. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    14. 14. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    15. 15. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    16. 16. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    17. 17. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine not ok 4 - Should have a state # Failed test 'Should have a state' # at t/try.t line 12. ok 5 - Should be able to reset # Looks like you failed 1 test of 5.
    18. 18. TAP Output
    19. 19. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine ok 4 - Should have a state ok 5 - Should be able to reset
    20. 20. TAP Output % perl -Ilib t/try.t 1..5 ok 1 - use FSA::Rules; ok 2 - Create FSA::Rules object ok 3 - Start the machine ok 4 - Should have a state ok 5 - Should be able to reset Think they passed?
    21. 21. Writing Tests
    22. 22. Writing Tests use Test::More tests => 5; use_ok 'FSA::Rules'; ok my $r = FSA::Rules->new, 'Create FSA::Rules object'; ok $r->start, 'Start the machine'; ok $r->curr_state, 'Should have a state'; ok $r->reset, 'Should be able to reset';
    23. 23. Writing Tests use Test::More tests => 5; use_ok 'FSA::Rules'; ok my $r = FSA::Rules->new, 'Create FSA::Rules object'; ok $r->start, 'Start the machine'; ok $r->curr_state, 'Should have a state'; ok $r->reset, 'Should be able to reset';
    24. 24. Writing Tests use Test::More tests => 5; use_ok 'FSA::Rules'; ok my $r = FSA::Rules->new, 'Create FSA::Rules object'; ok $r->start, 'Start the machine'; ok $r->curr_state, 'Should have a state'; ok $r->reset, 'Should be able to reset';
    25. 25. Writing Tests use Test::More tests => 5; use_ok 'FSA::Rules'; ok my $r = FSA::Rules->new, 'Create FSA::Rules object'; ok $r->start, 'Start the machine'; ok $r->curr_state, 'Should have a state'; ok $r->reset, 'Should be able to reset';
    26. 26. Writing Tests use Test::More tests => 5; use_ok 'FSA::Rules'; ok my $r = FSA::Rules->new, 'Create FSA::Rules object'; ok $r->start, 'Start the machine'; ok $r->curr_state, 'Should have a state'; ok $r->reset, 'Should be able to reset';
    27. 27. Writing Tests use Test::More tests => 5; use_ok 'FSA::Rules'; ok my $r = FSA::Rules->new, 'Create FSA::Rules object'; ok $r->start, 'Start the machine'; ok $r->curr_state, 'Should have a state'; ok $r->reset, 'Should be able to reset'; Simple declarative syntax
    28. 28. pgTAP
    29. 29. pgTAP Includes most Test::More functions
    30. 30. pgTAP Includes most Test::More functions ok() — Boolean
    31. 31. pgTAP Includes most Test::More functions ok() — Boolean is() — Value comparison
    32. 32. pgTAP Includes most Test::More functions ok() — Boolean is() — Value comparison isnt() — NOT is()
    33. 33. pgTAP Includes most Test::More functions ok() — Boolean is() — Value comparison isnt() — NOT is() cmp_ok() — Compare with specific operator
    34. 34. pgTAP Includes most Test::More functions ok() — Boolean is() — Value comparison isnt() — NOT is() cmp_ok() — Compare with specific operator matches() — Regex comparison
    35. 35. pgTAP Includes most Test::More functions ok() — Boolean is() — Value comparison isnt() — NOT is() cmp_ok() — Compare with specific operator matches() — Regex comparison imatches() — Case-insensitive regex comparison
    36. 36. pgTAP
    37. 37. pgTAP Includes Test controls
    38. 38. pgTAP Includes Test controls plan() — How many tests?
    39. 39. pgTAP Includes Test controls plan() — How many tests? no_plan() — Unknown number of tests
    40. 40. pgTAP Includes Test controls plan() — How many tests? no_plan() — Unknown number of tests diag() — Diagnostic output
    41. 41. pgTAP Includes Test controls plan() — How many tests? no_plan() — Unknown number of tests diag() — Diagnostic output finish() — Test finished, report!
    42. 42. Follow Along! http:/ /pgtap.projects.postgresql.org/
    43. 43. Installing pgTAP
    44. 44. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2
    45. 45. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22
    46. 46. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap SE_PGXS=1 U
    47. 47. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap SE_PGXS=1 U If in contrib…
    48. 48. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap If in contrib…
    49. 49. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap % sudo make install
    50. 50. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap % sudo make install % make installcheck
    51. 51. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap % sudo make install % make installcheck % psql -d template1 -d pgtap.sql
    52. 52. Installing pgTAP % tar jxf pgtap-0.22.tar.bz2 % cd pgtap-0.22 % make TAPSCHEMA=tap % sudo make install % make installcheck % psql -d template1 -d pgtap.sql Need postgresql-dev
    53. 53. pgTAP Basics
    54. 54. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK;
    55. 55. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK;
    56. 56. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK;
    57. 57. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK;
    58. 58. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK;
    59. 59. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK;
    60. 60. pgTAP Basics BEGIN; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK; If TAPSCHEMA…
    61. 61. pgTAP Basics BEGIN; SET search_path TO tap, public; -- Plan the tests. SELECT plan(1); --SELECT * FROM no_plan(); SELECT ok( true, 'Truth should be true' ); -- Clean up. SELECT * FROM finish(); ROLLBACK; If TAPSCHEMA…
    62. 62. Running Tests
    63. 63. Running Tests % pg_prove -v -d try try.sql try.sql .. psql:try.sql:5: ERROR: function plan(integer) does not exist LINE 1: SELECT plan(1); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. Dubious, test returned 3 (wstat 768, 0x300) No subtests run Test Summary Report ------------------- try.sql (Wstat: 768 Tests: 0 Failed: 0) Non-zero exit status: 3 Parse errors: No plan found in TAP output Files=1, Tests=0, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL
    64. 64. Running Tests % pg_prove -v -d try try.sql try.sql .. psql:try.sql:5: ERROR: function plan(integer) does not exist LINE 1: SELECT plan(1); ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. Dubious, test returned 3 (wstat 768, 0x300) No subtests run Oops Test Summary Report ------------------- try.sql (Wstat: 768 Tests: 0 Failed: 0) Non-zero exit status: 3 Parse errors: No plan found in TAP output Files=1, Tests=0, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: FAIL
    65. 65. Running Tests %
    66. 66. Running Tests %export PGOPTIONS=--search_path=tap,public %
    67. 67. Running Tests %export PGOPTIONS=--search_path=tap,public %pg_prove -v -d try try.sql try.sql .. 1..1 ok 1 - Truth should be true ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS
    68. 68. Running Tests %export PGOPTIONS=--search_path=tap,public %pg_prove -v -d try try.sql try.sql .. 1..1 ok 1 - Truth should be true ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS W00t!
    69. 69. Failure
    70. 70. Failure BEGIN; SELECT plan(2); SELECT ok( 1 + 1 = 2 ); SELECT ok( 2 + 2 = 5 ); SELECT * FROM finish(); ROLLBACK;
    71. 71. Failing Tests
    72. 72. Failing Tests %
    73. 73. Failing Tests %pg_prove -v -d try fail.sql fail.sql .. 1..2 ok 1 not ok 2 # Failed test 2 # Looks like you failed 1 test of 2 Failed 1/2 subtests
    74. 74. Failing Tests %pg_prove -v -d try fail.sql fail.sql .. 1..2 ok 1 not ok 2 # Failed test 2 # Looks like you failed 1 test of 2 Failed 1/2 subtests
    75. 75. Failing Tests %pg_prove -v -d try fail.sql fail.sql .. 1..2 ok 1 not ok 2 # Failed test 2 # Looks like you failed 1 test of 2 Failed 1/2 subtests
    76. 76. Failing Tests %pg_prove -v -d try fail.sql fail.sql .. 1..2 ok 1 not ok 2 # Failed test 2 # Looks like you failed 1 test of 2 Failed 1/2 subtests
    77. 77. Failing Tests %pg_prove -v -d try fail.sql fail.sql .. 1..2 ok 1 not ok 2 # Failed test 2 # Looks like you failed 1 test of 2 Failed 1/2 subtests
    78. 78. Scalar Testing
    79. 79. Scalar Testing Where to start testing?
    80. 80. Scalar Testing Where to start testing? Start with one unit of code
    81. 81. Scalar Testing Where to start testing? Start with one unit of code Maybe a custom data type
    82. 82. Scalar Testing Where to start testing? Start with one unit of code Maybe a custom data type Obvious candidate for scalar testing
    83. 83. Scalar Testing Where to start testing? Start with one unit of code Maybe a custom data type Obvious candidate for scalar testing Testing scalar values
    84. 84. Testing hstore
    85. 85. Testing hstore BEGIN; SELECT plan(2); SELECT ok( 'k => 1'::hstore IS NOT NULL ); SELECT ok( pg_typeof('k' => '2') = 'hstore'::regtype ); SELECT * FROM finish(); ROLLBACK;
    86. 86. Testing hstore
    87. 87. Testing hstore %
    88. 88. Testing hstore %pg_prove -v -d try hstore.sql hstore.sql .. 1..2 ok 1 ok 2 ok All tests successful.
    89. 89. Testing hstore %pg_prove -v -d try hstore.sql hstore.sql .. 1..2 ok 1 ok 2 ok All tests successful. Your first useful test
    90. 90. Describe Yourself
    91. 91. Describe Yourself SELECT plan(2); SELECT ok( 'k => 1'::hstore IS NOT NULL, 'hstore should work' ); SELECT ok( pg_typeof('k' => '2') = 'hstore'::regtype, '=> should create hstore' ); SELECT * FROM finish();
    92. 92. Describe Yourself
    93. 93. Describe Yourself %
    94. 94. Describe Yourself %pg_prove -v -d try hstore.sql hstore.sql .. 1..2 ok 1 - hstore should work ok 2 - => should create hstore ok All tests successful.
    95. 95. Simplify, Simplify SELECT plan(2); SELECT ok( 'k => 1'::hstore IS NOT NULL, 'hstore should work' ); SELECT ok( pg_typeof('k' => '2') = 'hstore'::regtype, '=> should create hstore' ); SELECT * FROM finish();
    96. 96. Simplify, Simplify SELECT plan(2); SELECT ok( 'k => 1'::hstore IS NOT NULL, 'hstore should work' ); SELECT isa_ok( 'k' => '2', 'hstore', '=> return value' ); SELECT * FROM finish();
    97. 97. Simplify, Simplify
    98. 98. Simplify, Simplify %
    99. 99. Simplify, Simplify %pg_prove -v -d try hstore.sql hstore.sql .. 1..2 ok 1 - hstore should work ok 2 - => return value isa hstore ok All tests successful.
    100. 100. Test the Manual
    101. 101. Test the Manual SELECT plan(6); SELECT ok( 'a=>x, b=>y'::hstore -> 'a' = 'x', 'op ->' ); SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT ok( akeys('a=>1,b=>2') = '{a,c}', 'akeys()' ); SELECT ok( avals('a=>1,b=>2') = '{1,2}', 'avals()' ); SELECT * FROM finish();
    102. 102. Test the Manual
    103. 103. Test the Manual %
    104. 104. Test the Manual %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> ok 4 - op <@ not ok 5 - akeys() # Failed test 5: "akeys()" ok 6 - avals() # Looks like you failed 1 test of 6 Failed 1/6 subtests
    105. 105. Test the Manual %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> Um, why? ok 4 - op <@ not ok 5 - akeys() # Failed test 5: "akeys()" ok 6 - avals() # Looks like you failed 1 test of 6 Failed 1/6 subtests
    106. 106. What is() It? SELECT plan(6); SELECT ok'a=>x, b=>y'::hstore -> 'a' 'x', 'op ->' ); ( = SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT okakeys('a=>1,b=>2') '{a,c}', 'akeys()' ); ( = SELECT okavals('a=>1,b=>2') '{1,2}', 'avals()' ); ( = SELECT * FROM finish();
    107. 107. What is() It? SELECT plan(6); SELECT is 'a=>x, b=>y'::hstore -> 'a' 'x', ,'op ->' ); ( SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT is akeys('a=>1,b=>2') '{a,c}', 'akeys()' ); ( , SELECT is avals('a=>1,b=>2') '{1,2}', 'avals()' ); ( , SELECT * FROM finish();
    108. 108. %
    109. 109. %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> ok 4 - op <@ not ok 5 - akeys() # Failed test 5: "akeys()" # have: {a,b} # want: {a,c} ok 6 - avals() # Looks like you failed 1 test of 6 Failed 1/6 subtests
    110. 110. %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> ok 4 - op <@ not ok 5 - akeys() # Failed test 5: "akeys()" # have: {a,b} # want: {a,c} ok 6 - avals() # Looks like you failed 1 test of 6 Failed 1/6 subtests
    111. 111. %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> There it is ok 4 - op <@ not ok 5 - akeys() # Failed test 5: "akeys()" # have: {a,b} # want: {a,c} ok 6 - avals() # Looks like you failed 1 test of 6 Failed 1/6 subtests
    112. 112. What is() It? SELECT plan(6); SELECT is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' ); SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT c is( akeys('a=>1,b=>2'), '{a, }', 'akeys()' ); SELECT is( avals('a=>1,b=>2'), '{1,2}', 'avals()' ); SELECT * FROM finish();
    113. 113. What is() It? SELECT plan(6); SELECT is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' ); SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT c is( akeys('a=>1,b=>2'), '{a, }', 'akeys()' ); SELECT is( avals('a=>1,b=>2'), '{1,2}', 'avals()' ); SELECT * FROM finish();
    114. 114. What is() It? SELECT plan(6); SELECT is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' ); SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT c is( akeys('a=>1,b=>2'), '{a, }', 'akeys()' ); SELECT is( avals('a=>1,b=>2'), '{1,2}', 'avals()' ); SELECT * FROM finish();
    115. 115. What is() It? SELECT plan(6); SELECT is( 'a=>x, b=>y'::hstore -> 'a', 'x', 'op ->' ); SELECT ok( 'a=>1'::hstore ? 'a', 'op ?' ); SELECT ok( 'a=>b, b=>1'::hstore @> 'b=>1', 'op @>' ); SELECT ok( NOT 'a=>c'::hstore <@ 'a=>b, b=>1', 'op <@' ); SELECT b is( akeys('a=>1,b=>2'), '{a, }', 'akeys()' ); SELECT is( avals('a=>1,b=>2'), '{1,2}', 'avals()' ); SELECT * FROM finish();
    116. 116. What is() It?
    117. 117. What is() It? %
    118. 118. What is() It? %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> ok 4 - op <@ ok 5 - akeys() ok 6 - avals() ok All tests successful.
    119. 119. What is() It? %pg_prove -v -d try hstore.sql hstore.sql .. 1..6 ok 1 - op -> ok 2 - op ? ok 3 - op @> Much better! ok 4 - op <@ ok 5 - akeys() ok 6 - avals() ok All tests successful.
    120. 120. Repetition
    121. 121. Repetition Want to test lots of values
    122. 122. Repetition Want to test lots of values Try to trick code with edge cases
    123. 123. Repetition Want to test lots of values Try to trick code with edge cases Writing same tests with different values
    124. 124. Repetition Want to test lots of values Try to trick code with edge cases Writing same tests with different values Could get old fast
    125. 125. Repetition Want to test lots of values Try to trick code with edge cases Writing same tests with different values Could get old fast Use a table for repetitive tests
    126. 126. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    127. 127. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    128. 128. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    129. 129. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, -- val -> arrow_rop arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    130. 130. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, -- val -> arrow_rop arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    131. 131. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, -- val -> arrow_rop arrow_val text, -- = arrow_val qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    132. 132. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    133. 133. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, -- val ? qmark_rop akeys_val text[], avals_val text[] ); RESET client_min_messages;
    134. 134. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    135. 135. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], -- akeys(val) = akeys_val avals_val text[] ); RESET client_min_messages;
    136. 136. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages;
    137. 137. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] -- avals(val) = avals_val ); RESET client_min_messages;
    138. 138. SET client_min_messages = warning; CREATE TEMPORARY TABLE hs_tests ( val hstore, arrow_rop text, arrow_val text, qmark_rop text, akeys_val text[], avals_val text[] ); RESET client_min_messages; -- Insert test values. INSERT INTO hs_tests VALUES ('a=>1,b=>2', 'a', '1', 'a', '{a,b}', '{1,2}'), ('a=>1', 'a', '1', 'a', '{a}', '{1}') ;
    139. 139. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    140. 140. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    141. 141. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    142. 142. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    143. 143. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    144. 144. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    145. 145. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    146. 146. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    147. 147. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    148. 148. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    149. 149. SELECT plan(COUNT(*)::int * 4) FROM hs_tests; SELECT is( val -> arrow_rop, arrow_val, quote_literal(val) || ' ? ' || quote_literal(arrow_val) ) FROM hs_tests; SELECT ok( val ? qmark_rop, quote_literal(val) || ' -> ' || quote_literal(qmark_rop) ) FROM hs_tests; SELECT is( akeys(val), akeys_val, 'akeys(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT is( avals(val), avals_val, 'avals(' || quote_literal(val) || ')' ) FROM hs_tests; SELECT * FROM finish();
    150. 150. Repetition
    151. 151. Repetition %
    152. 152. Repetition %pg_prove -v -d try hstore.sql hstore.sql .. 1..8 ok 1 - '"a"=>"1", "b"=>"2"' ? '1' ok 2 - '"a"=>"1"' ? '1' ok 3 - '"a"=>"1", "b"=>"2"' -> 'a' ok 4 - '"a"=>"1"' -> 'a' ok 5 - akeys('"a"=>"1", "b"=>"2"') ok 6 - akeys('"a"=>"1"') ok 7 - avals('"a"=>"1", "b"=>"2"') ok 8 - avals('"a"=>"1"') ok All tests successful.
    153. 153. Add Tests -- Insert test values. INSERT INTO hs_tests VALUES ('a=>1,b=>2', 'a', '1', 'a', '{a,b}', '{1,2}'), ('a=>1', 'a', '1', 'a', '{a}', '{1}')
    154. 154. Add Tests -- Insert test values. INSERT INTO hs_tests VALUES ('a=>1,b=>2', 'a', '1', 'a', '{a,b}', '{1,2}'), ('a=>1', 'a', '1', 'a', '{a}', '{1}') , ('foo=>bar', 'foo', 'bar', 'foo', '{foo}', '{bar}'), ('1=>a,2=>b', '1', 'a', '1', '{1,2}', '{a,b}'), ( 'name=>"Tom Lane",rank=>"H@xi3",sn=>ou812', 'rank', 'H@xi3', 'name', '{sn,name,rank}', '{ou812,"Tom Lane",H@xi3}' );
    155. 155. More Repetition
    156. 156. More Repetition %
    157. 157. More Repetition %pg_prove -d try hstore.sql hstore.sql .. All tests successful. Files=1, Tests=20, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS
    158. 158. More Repetition %pg_prove -d try hstore.sql hstore.sql .. All tests successful. Files=1, Tests=20, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS
    159. 159. More Repetition %pg_prove -d try hstore.sql hstore.sql .. All tests successful. Files=1, Tests=20, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS
    160. 160. Skipping Tests
    161. 161. Skipping Tests Sometimes need to skip tests
    162. 162. Skipping Tests Sometimes need to skip tests Platform dependencies
    163. 163. Skipping Tests Sometimes need to skip tests Platform dependencies Collation dependencies
    164. 164. Skipping Tests Sometimes need to skip tests Platform dependencies Collation dependencies Version dependencies
    165. 165. Skipping Tests Sometimes need to skip tests Platform dependencies Collation dependencies Version dependencies Use skip()
    166. 166. Skipping Tests
    167. 167. Skipping Tests SELECT CASE os_name() WHEN 'darwin' THEN cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o') ELSE skip('Collation-specific test') END;
    168. 168. Skipping Tests SELECT CASE os_name() WHEN 'darwin' THEN cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o') ELSE skip('Collation-specific test') END;
    169. 169. Skipping Tests SELECT CASE os_name() WHEN 'darwin' THEN cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o') ELSE skip('Collation-specific test') END;
    170. 170. Skipping Tests SELECT CASE os_name() WHEN 'darwin' THEN cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o') ELSE skip('Collation-specific test') END;
    171. 171. Skipping Tests SELECT CASE os_name() WHEN 'darwin' THEN cmp_ok('Bjørn'::text, '>', 'Bjorn','ø > o') ELSE skip('Collation-specific test') END;
    172. 172. Skipping Tests
    173. 173. Skipping Tests %
    174. 174. Skipping Tests %pg_prove -v -d try collation.sql collation.sql .. 1..1 ok 1 - ø > o ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.01 sys = 0.03 CPU) Result: PASS
    175. 175. Skipping Tests %pg_prove -v -d try collation.sql collation.sql .. 1..1 ok 1 - ø > o ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.01 sys = 0.03 CPU) Result: PASS
    176. 176. Skipping Tests %pg_prove -v -d try collation.sql collation.sql .. 1..1 ok 1 - ø > o ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.01 sys = 0.03 CPU) Result: PASS ✔ Darwin
    177. 177. Skipping Tests
    178. 178. Skipping Tests %
    179. 179. Skipping Tests %pg_prove -v -d try collation.sql collation.sql .. 1..1 ok 1 - SKIP: Collation-specific test ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS
    180. 180. Skipping Tests %pg_prove -v -d try collation.sql collation.sql .. 1..1 ok 1 - SKIP: Collation-specific test ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS
    181. 181. Skipping Tests %pg_prove -v -d try collation.sql collation.sql .. 1..1 ok 1 - SKIP: Collation-specific test ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.02 usr + 0.00 sys = 0.02 CPU) Result: PASS ! Darwin
    182. 182. Skip More
    183. 183. Skip More SELECT CASE os_name() WHEN 'darwin' THEN array_to_string( ARRAY[ cmp_ok( 'Bjørn'::text, '>', 'Bjorn', 'ø > o' ), cmp_ok( 'Pınar'::text, '>', 'Pinar', 'ı > i' ), cmp_ok( 'José'::text, '>', 'Jose', 'é > e' ), cmp_ok( 'Täp'::text, '>', 'Tap', 'ä > a' ) ], E'n' ) ELSE skip('Collation-specific test', 4) END;
    184. 184. Skip More
    185. 185. Skip More %
    186. 186. Skip More %pg_prove -v -d try collation.sql collation.sql .. 1..4 ok 1 - ø > o ok 2 - ı > i ok 3 - é > e ok 4 - ä > a ok All tests successful.
    187. 187. Skip More %pg_prove -v -d try collation.sql collation.sql .. 1..4 ok 1 - ø > o ok 2 - ı > i ok 3 - é > e ok 4 - ä > a ok All tests successful. ✔ Darwin
    188. 188. Skip More
    189. 189. Skip More %
    190. 190. Skip More %pg_prove -v -d try collation.sql collation.sql .. 1..4 ok 1 - SKIP: Collation-specific test ok 2 - SKIP: Collation-specific test ok 3 - SKIP: Collation-specific test ok 4 - SKIP: Collation-specific test ok All tests successful.
    191. 191. Skip More %pg_prove -v -d try collation.sql collation.sql .. 1..4 ok 1 - SKIP: Collation-specific test ok 2 - SKIP: Collation-specific test ok 3 - SKIP: Collation-specific test ok 4 - SKIP: Collation-specific test ok All tests successful. ! Darwin
    192. 192. Todo Tests
    193. 193. Todo Tests Sometimes need to ignore failures
    194. 194. Todo Tests Sometimes need to ignore failures Features not implemented
    195. 195. Todo Tests Sometimes need to ignore failures Features not implemented Unfixed regression
    196. 196. Todo Tests Sometimes need to ignore failures Features not implemented Unfixed regression Version dependences
    197. 197. Todo Tests Sometimes need to ignore failures Features not implemented Unfixed regression Version dependences Use todo()
    198. 198. Todo Tests
    199. 199. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    200. 200. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    201. 201. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    202. 202. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    203. 203. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    204. 204. Todo Tests
    205. 205. Todo Tests %
    206. 206. Todo Tests %pg_prove -v -d try text.sql text.sql .. ok 1 - text is text isa text ok 2 - $$ is text isa text not ok 3 - should be text # Failed test 3: "should be text" # have: unknown # want: text not ok 4 - $$ should be text # Failed test 4: "$$ should be text" # have: unknown # want: text # Looks like you failed 2 tests of 4 Failed 2/4 subtests
    207. 207. Todo Tests %pg_prove -v -d try text.sql text.sql .. Will get ok 1 - text is text isa text ok 2 - $$ is text isa text not ok 3 - should be text around to # Failed test 3: "should be text" # have: unknown those… # want: text not ok 4 - $$ should be text # Failed test 4: "$$ should be text" # have: unknown # want: text # Looks like you failed 2 tests of 4 Failed 2/4 subtests
    208. 208. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    209. 209. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT * FROM todo('not written yet', 2 ); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    210. 210. Todo Tests
    211. 211. Todo Tests %
    212. 212. Todo Tests %pg_prove -v -d try text.sql text.sql .. 1..4 ok 1 - text is text isa text ok 2 - $$ is text isa text not ok 3 - should be text # TODO not written yet # Failed (TODO) test 3: "should be text" # have: unknown # want: text not ok 4 - $$ should be text # TODO not written yet # Failed (TODO) test 4: "$$ should be text" # have: unknown # want: text ok All tests successful.
    213. 213. Todo Tests %pg_prove -v -d try text.sql text.sql .. 1..4 ok 1 - text is text isa text ok 2 - $$ is text isa text not ok 3 - should be text # TODO not written yet # Failed (TODO) test 3: "should be text" # have: unknown # want: text not ok 4 - $$ should be text # TODO not written yet # Failed (TODO) test 4: "$$ should be text" # have: unknown # want: text ok All tests successful.
    214. 214. Todo Tests %pg_prove -v -d try text.sql text.sql .. 1..4 ok 1 - text is text isa text ok 2 - $$ is text isa text not ok 3 - should be text # TODO not written yet # Failed (TODO) test 3: "should be text" # have: unknown # want: text not ok 4 - $$ should be text # TODO not written yet # Failed (TODO) test 4: "$$ should be text" # ` have: unknown # want: text ok All tests successful.
    215. 215. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); ('not written yet' SELECT * FROM todo , 2 ); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text');
    216. 216. Todo Tests SELECT plan(4); SELECT isa_ok('foo'::text, 'text', 'text is text'); SELECT isa_ok($$foo$$::text, 'text', '$$ is text'); SELECT ('not written yet' * FROM todo_start ); SELECT is( pg_typeof('foo'), 'text', 'should be text'); SELECT is( pg_typeof($$foo$$), 'text', '$$ should be text'); SELECT * FROM todo_end();
    217. 217. Todo Tests
    218. 218. Todo Tests %
    219. 219. Todo Tests %pg_prove -v -d try text.sql text.sql .. 1..4 ok 1 - text is text isa text ok 2 - $$ is text isa text not ok 3 - should be text # TODO not written yet # Failed (TODO) test 3: "should be text" # have: unknown # want: text not ok 4 - $$ should be text # TODO not written yet # Failed (TODO) test 4: "$$ should be text" # have: unknown # want: text ok All tests successful.
    220. 220. Other Goodies
    221. 221. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    222. 222. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    223. 223. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    224. 224. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    225. 225. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    226. 226. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    227. 227. Other Goodies SELECT * FROM no_plan(); SELECT matches( :zip_code, '^[[:digit:]]{5}$' ); SELECT alike( :country, 'United %' ); SELECT throws_ok( 'SELECT lower(10.2)', '42883' ); SELECT throws_ok( 'SELECT lower(10.2)', 'function lower(numeric) does not exist' ); SELECT lives_ok( 'SELECT 2 + 2', 'It''s alive!' ); SELECT diag( 'OMG TAP WTF?' ); SELECT performs_ok( 'SELECT fib(32)', 500 ); SELECT * FROM finish();
    228. 228. Other Goodies
    229. 229. Other Goodies %
    230. 230. Other Goodies %pg_prove -v -d try goodies.sql goodies.sql .. ok 1 ok 2 ok 3 - threw 42883 ok 4 - threw function lower(numeric) does not exist ok 5 - It's alive! # OMG TAP WTF? ok 6 - Should run in less than 500 ms 1..6 ok All tests successful.
    231. 231. Other Goodies %pg_prove -v -d try goodies.sql goodies.sql .. ok 1 ok 2 ok 3 - threw 42883 ok 4 - threw function lower(numeric) does not exist ok 5 - It's alive! # OMG TAP WTF? ok 6 - Should run in less than 500 ms 1..6 ok All tests successful.
    232. 232. Other Goodies %pg_prove -v -d try goodies.sql goodies.sql .. ok 1 ok 2 ok 3 - threw 42883 ok 4 - threw function lower(numeric) does not exist ok 5 - It's alive! # OMG TAP WTF? ok 6 - Should run in less than 500 ms 1..6 ok All tests successful.
    233. 233. Other Goodies %pg_prove -v -d try goodies.sql goodies.sql .. ok 1 ok 2 ok 3 - threw 42883 ok 4 - threw function lower(numeric) does not exist ok 5 - It's alive! # OMG TAP WTF? ok 6 - Should run in less than 500 ms 1..6 ok All tests successful.
    234. 234. Other Goodies %pg_prove -v -d try goodies.sql goodies.sql .. ok 1 ok 2 ok 3 - threw 42883 ok 4 - threw function lower(numeric) does not exist ok 5 - It's alive! # OMG TAP WTF? ok 6 - Should run in less than 500 ms 1..6 ok All tests successful.
    235. 235. Pursuing your Query
    236. 236. Pursuing your Query Several functions execute queries
    237. 237. Pursuing your Query Several functions execute queries Seen throws_ok(), lives_ok(), performs_ok()
    238. 238. Pursuing your Query Several functions execute queries Seen throws_ok(), lives_ok(), performs_ok() Take SQL statement argument
    239. 239. Pursuing your Query Several functions execute queries Seen throws_ok(), lives_ok(), performs_ok() Take SQL statement argument PITA for complicated queries
    240. 240. Pursuing your Query Several functions execute queries Seen throws_ok(), lives_ok(), performs_ok() Take SQL statement argument PITA for complicated queries Single quotes a particular PITA
    241. 241. Pursuing your Query Several functions execute queries Seen throws_ok(), lives_ok(), performs_ok() Take SQL statement argument PITA for complicated queries Single quotes a particular PITA Alternative: Prepared Statements
    242. 242. Pursuing your Query
    243. 243. Pursuing your Query PREPARE new_user AS INSERT INTO users (nick, pass, name) VALUES ('theory', 's3kr1t', 'David Wheeler'); EXECUTE new_user; SELECT throws_ok ('new_user');
    244. 244. Pursuing your Query PREPARE new_user AS INSERT INTO users (nick, pass, name) VALUES ('theory', 's3kr1t', 'David Wheeler'); EXECUTE new_user; SELECT throws_ok ('new_user');
    245. 245. Pursuing your Query PREPARE new_user AS INSERT INTO users (nick, pass, name) VALUES ('theory', 's3kr1t', 'David Wheeler'); EXECUTE new_user; SELECT throws_ok ('new_user');
    246. 246. Pursuing your Query PREPARE new_user AS INSERT INTO users (nick, pass, name) VALUES ('theory', 's3kr1t', 'David Wheeler'); EXECUTE new_user; SELECT throws_ok ('new_user');
    247. 247. Testing Relations
    248. 248. Testing Relations Not everything is a scalar
    249. 249. Testing Relations Not everything is a scalar It’s a RELATIONAL database, after all
    250. 250. Testing Relations Not everything is a scalar It’s a RELATIONAL database, after all Only so much coercion to scalars to do
    251. 251. Testing Relations Not everything is a scalar It’s a RELATIONAL database, after all Only so much coercion to scalars to do Need to test
    252. 252. Testing Relations Not everything is a scalar It’s a RELATIONAL database, after all Only so much coercion to scalars to do Need to test results
    253. 253. Testing Relations Not everything is a scalar It’s a RELATIONAL database, after all Only so much coercion to scalars to do Need to test results sets
    254. 254. Testing Relations Not everything is a scalar It’s a RELATIONAL database, after all Only so much coercion to scalars to do Need to test results sets bags
    255. 255. results_eq()
    256. 256. results_eq() Tests query results
    257. 257. results_eq() Tests query results Row-by-row comparison
    258. 258. results_eq() Tests query results Row-by-row comparison In order
    259. 259. results_eq() Tests query results Row-by-row comparison In order Test query and expected query may be:
    260. 260. results_eq() Tests query results Row-by-row comparison In order Test query and expected query may be: SQL statements
    261. 261. results_eq() Tests query results Row-by-row comparison In order Test query and expected query may be: SQL statements Prepared statement names
    262. 262. results_eq() Tests query results Row-by-row comparison In order Test query and expected query may be: SQL statements Prepared statement names Cursor names
    263. 263. Testing Results
    264. 264. Testing Results Example: active_users()
    265. 265. Testing Results Example: active_users() Returns set of active users
    266. 266. Testing Results Example: active_users() Returns set of active users Test the function
    267. 267. Testing Results Example: active_users() Returns set of active users Test the function Compare results
    268. 268. results_eq() Arguments
    269. 269. results_eq() Arguments SELECT results_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active ORDER BY nick', 'active_users() should return active users' );
    270. 270. results_eq() Arguments SELECT results_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active ORDER BY nick', 'active_users() should return active users' );
    271. 271. results_eq() Arguments SELECT results_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active ORDER BY nick', 'active_users() should return active users' );
    272. 272. results_eq() Arguments SELECT results_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active ORDER BY nick', 'active_users() should return active users' ); SELECT results_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' );
    273. 273. results_eq() Arguments SELECT results_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active ORDER BY nick', 'active_users() should return active users' ); SELECT results_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' );
    274. 274. results_eq() Arguments
    275. 275. results_eq() Arguments PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active ORDER BY nick;
    276. 276. results_eq() Arguments PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active ORDER BY nick;
    277. 277. results_eq() Arguments PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active ORDER BY nick;
    278. 278. results_eq() Arguments PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active ORDER BY nick; SELECT results_eq( 'users_test', 'users_expect', 'We should have users' );
    279. 279. results_eq() Arguments PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active ORDER BY nick; SELECT results_eq( 'users_test', 'users_expect', 'We should have users' );
    280. 280. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick;
    281. 281. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick;
    282. 282. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick;
    283. 283. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick; SELECT results_eq( 'EXECUTE get_users_test(true)', 'EXECUTE get_users_expect(true)', 'We should have active users' );
    284. 284. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick; SELECT results_eq( 'EXECUTE get_users_test(true)', 'EXECUTE get_users_expect(true)', 'We should have active users' );
    285. 285. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick; SELECT results_eq( 'EXECUTE get_users_test(true)', 'EXECUTE get_users_expect(true)', 'We should have active users' );
    286. 286. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick; SELECT results_eq( 'EXECUTE get_users_test(true)', 'EXECUTE get_users_expect(true)', 'We should have active users' ); SELECT results_eq( 'EXECUTE get_users_test(false)', 'EXECUTE get_users_expect(false)', 'We should have inactive users' );
    287. 287. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick; SELECT results_eq( 'EXECUTE get_users_test(true)', 'EXECUTE get_users_expect(true)', 'We should have active users' ); SELECT results_eq( 'EXECUTE get_users_test(false)', 'EXECUTE get_users_expect(false)', 'We should have inactive users' );
    288. 288. PREPARE get_users_test(boolean) AS SELECT * FROM get_users($1); PREPARE get_users_expect(boolean) AS SELECT * FROM users WHERE active = $1 ORDER BY nick; SELECT results_eq( 'EXECUTE get_users_test(true)', 'EXECUTE get_users_expect(true)', 'We should have active users' ); SELECT results_eq( 'EXECUTE get_users_test(false)', 'EXECUTE get_users_expect(false)', 'We should have inactive users' );
    289. 289. results_eq() Single Column & Array
    290. 290. results_eq() Single Column & Array SELECT results_eq( 'SELECT * FROM active_user_nicks()', ARRAY[ 'anna', 'strongrrl', 'theory' ], 'Should have active nicks' );
    291. 291. results_eq() Single Column & Array SELECT results_eq( 'SELECT * FROM active_user_nicks()', ARRAY[ 'anna', 'strongrrl', 'theory' ], 'Should have active nicks' );
    292. 292. results_eq() Single Column & Array SELECT results_eq( 'SELECT * FROM active_user_nicks()', ARRAY[ 'anna', 'strongrrl', 'theory' ], 'Should have active nicks' );
    293. 293. Testing Results
    294. 294. Testing Results %
    295. 295. Testing Results %pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() should return active users ok 2 - active_users() should return active users ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 ok All tests successful.
    296. 296. Differing Rows Diagnostics %
    297. 297. Differing Rows Diagnostics % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() should return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Results differ beginning at row 2: # have: (strongrrl,portland,"Julie Wheeler",t) # want: (strongrrl,design,"Julie Wheeler",t) ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    298. 298. Differing Rows Diagnostics % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() should return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Results differ beginning at row 2: # have: (strongrrl,portland,"Julie Wheeler",t) # want: (strongrrl,design,"Julie Wheeler",t) ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    299. 299. Differing Columns Diagnostics %
    300. 300. Differing Columns Diagnostics % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (anna,yddad,"Anna Wheeler",t) # want: (anna,yddad,"Anna Wheeler") ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    301. 301. Differing Columns Diagnostics % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (anna,yddad,"Anna Wheeler",t) # want: (anna,yddad,"Anna Wheeler") ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    302. 302. Missing Row Diagnostics %
    303. 303. Missing Row Diagnostics % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Results differ beginning at row 3: # have: (theory,s3kr1t,"David Wheeler",t) # want: NULL ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    304. 304. Missing Row Diagnostics % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Results differ beginning at row 3: # have: (theory,s3kr1t,"David Wheeler",t) # want: NULL ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    305. 305. Diagnostics for Differing Data Types %
    306. 306. Diagnostics for Differing Data Types % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (anna,yddad,"Anna Wheeler",t) # want: (anna,yddad,"Anna Wheeler",t) ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    307. 307. Diagnostics for Differing Data Types % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (anna,yddad,"Anna Wheeler",t) # want: (anna,yddad,"Anna Wheeler",t) ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks 1..6 # Looks like you failed 1 test of 6 Failed 1/6 subtests
    308. 308. Diagnostics for Differing Data Types % pg_prove -v -d try results_eq.sql results_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (anna,yddad,"Anna Wheeler",t) # want: (anna,yddad,"Anna Wheeler",t) ok 3 - We should have users ok 4 - We should have active users ok 5 - We should have inactive users ok 6 - Should have active nicks Say 1..6 # Looks like you failed 1 test of 6 what? Failed 1/6 subtests
    309. 309. Testing Sets
    310. 310. Testing Sets When order does not matter
    311. 311. Testing Sets When order does not matter When duplicate tuples do not matter
    312. 312. Testing Sets When order does not matter When duplicate tuples do not matter Use queries
    313. 313. Testing Sets When order does not matter When duplicate tuples do not matter Use queries Or prepared statement names
    314. 314. Testing Bags
    315. 315. Testing Bags When order does not matter
    316. 316. Testing Bags When order does not matter Duplicates matter
    317. 317. Testing Bags When order does not matter Duplicates matter Use queries
    318. 318. Testing Bags When order does not matter Duplicates matter Use queries Or prepared statement names
    319. 319. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' );
    320. 320. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' );
    321. 321. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' );
    322. 322. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' );
    323. 323. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' );
    324. 324. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' );
    325. 325. SELECT set_eq( 'SELECT * FROM active_users()', 'SELECT * FROM users WHERE active', 'active_users() should return active users' ); SELECT set_eq( 'SELECT * FROM active_users()', $$VALUES ('anna', 'yddad', 'Anna Wheeler', true), ('strongrrl', 'design', 'Julie Wheeler', true), ('theory', 's3kr1t', 'David Wheeler', true) $$, 'active_users() should return active users' ); PREPARE users_test AS SELECT * FROM active_users(); PREPARE users_expect AS SELECT * FROM users WHERE active; SELECT bag_eq( 'users_test', 'users_expect', 'We should have users' No ORDER BY );
    326. 326. Differing Rows Diagnostics %
    327. 327. Differing Rows Diagnostics % pg_prove -v -d try set_eq.sql set_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2 "active_users() return active users" # Extra records: # (87,Jackson) # (1,Jacob) # Missing records: # (44,Anna) # (86,Angelina) ok 3 - We should have users 1..3 # Looks like you failed 1 test of 3 Failed 1/3 subtests
    328. 328. Differing Rows Diagnostics % pg_prove -v -d try set_eq.sql set_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2 "active_users() return active users" # Extra records: # (87,Jackson) # (1,Jacob) # Missing records: # (44,Anna) # (86,Angelina) ok 3 - We should have users 1..3 # Looks like you failed 1 test of 3 Failed 1/3 subtests
    329. 329. Diagnostics for Differing Data Types %
    330. 330. Diagnostics for Differing Data Types %pg_prove -v -d try set_eq.sql set_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (integer,text) # want: (text,integer) ok 3 - We should have users 1..3 # Looks like you failed 1 test of 3 Failed 1/3 subtests
    331. 331. Diagnostics for Differing Data Types %pg_prove -v -d try set_eq.sql set_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (integer,text) # want: (text,integer) ok 3 - We should have users 1..3 # Looks like you failed 1 test of 3 Failed 1/3 subtests
    332. 332. Diagnostics for Different Numbers of Columns %
    333. 333. Diagnostics for Different Numbers of Columns %pg_prove -v -d try set_eq.sql set_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (integer) # want: (text,integer) ok 3 - We should have users 1..3 # Looks like you failed 1 test of 3 Failed 1/3 subtests
    334. 334. Diagnostics for Different Numbers of Columns %pg_prove -v -d try set_eq.sql set_eq.sql .. ok 1 - active_users() return active users not ok 2 - active_users() return active users # Failed test 2: "active_users() return active users" # Columns differ between queries: # have: (integer) # want: (text,integer) ok 3 - We should have users 1..3 # Looks like you failed 1 test of 3 Failed 1/3 subtests
    335. 335. Structural Testing
    336. 336. Structural Testing Validate presence/absence of objects
    337. 337. Structural Testing Validate presence/absence of objects *_are()
    338. 338. Structural Testing Validate presence/absence of objects *_are() Specify complete lists of objects
    339. 339. Structural Testing Validate presence/absence of objects *_are() Specify complete lists of objects Useful failure diagnostics
    340. 340. SELECT tablespaces_are( ARRAY[ 'dbspace', 'indexspace' ] );
    341. 341. SELECT tablespaces_are( ARRAY[ 'dbspace', 'indexspace' ] ); SELECT schemas_are( ARRAY[ 'public', 'contrib', 'biz' ] );
    342. 342. SELECT tablespaces_are( ARRAY[ 'dbspace', 'indexspace' ] ); SELECT schemas_are( ARRAY[ 'public', 'contrib', 'biz' ] ); SELECT tables_are( 'biz', ARRAY[ 'users', 'widgets' ] );
    343. 343. SELECT tablespaces_are( ARRAY[ 'dbspace', 'indexspace' ] ); SELECT schemas_are( ARRAY[ 'public', 'contrib', 'biz' ] ); SELECT tables_are( 'biz', ARRAY[ 'users', 'widgets' ] ); SELECT views_are( 'biz', ARRAY[ 'user_list', 'widget_list' ] );
    344. 344. SELECT tablespaces_are( ARRAY[ 'dbspace', 'indexspace' ] ); SELECT schemas_are( ARRAY[ 'public', 'contrib', 'biz' ] ); SELECT tables_are( 'biz', ARRAY[ 'users', 'widgets' ] ); SELECT views_are( 'biz', ARRAY[ 'user_list', 'widget_list' ] ); SELECT sequences_are( 'biz', ARRAY[ 'users_id_seq', 'widgets_id_seq' ] );
    345. 345. SELECT indexes_are( 'biz', 'users', ARRAY[ 'users_pkey' ] );
    346. 346. SELECT indexes_are( 'biz', 'users', ARRAY[ 'users_pkey' ] ); SELECT functions_are( 'biz', ARRAY[ 'get_users', 'get_widgets' ] );
    347. 347. SELECT indexes_are( 'biz', 'users', ARRAY[ 'users_pkey' ] ); SELECT functions_are( 'biz', ARRAY[ 'get_users', 'get_widgets' ] ); SELECT users_are( ARRAY[ 'postgres', 'david', 'bric' ] );
    348. 348. SELECT indexes_are( 'biz', 'users', ARRAY[ 'users_pkey' ] ); SELECT functions_are( 'biz', ARRAY[ 'get_users', 'get_widgets' ] ); SELECT users_are( ARRAY[ 'postgres', 'david', 'bric' ] ); SELECT groups_are( ARRAY[ admins', 'devs' ] );
    349. 349. Structural Testing
    350. 350. Structural Testing SELECT languages_are( ARRAY[ 'plpgsql', 'plperlu', 'plperl' ] );
    351. 351. Structural Testing SELECT languages_are( ARRAY[ 'plpgsql', 'plperlu', 'plperl' ] ); SELECT opclasses_are( 'biz', ARRAY[ 'biz_ops' ] );
    352. 352. Structural Testing SELECT languages_are( ARRAY[ 'plpgsql', 'plperlu', 'plperl' ] ); SELECT opclasses_are( 'biz', ARRAY[ 'biz_ops' ] ); SELECT rules_are( 'biz', 'users', ARRAY[ 'ins_me', 'upd_me' ] );
    353. 353. %
    354. 354. %pg_prove -v -d try schema.sql schema.sql .. ok 1 - There should be the correct schemas not ok 2 - Schema biz should have the correct tables # Failed test 2: "Schema biz should have the correct tables" # Extra tables: # mallots # __test_table # Missing tables: # users # widgets ok 3 - Schema biz should have the correct views ok 4 - Schema biz should have the correct sequences ok 5 - Table biz.users should have the correct indexes ok 6 - Schema biz should have the correct functions ok 7 - There should be the correct users ok 8 - There should be the correct groups ok 9 - There should be the correct procedural languages ok 10 - Schema biz should have the correct operator classes ok 11 - Relation biz.users should have the correct rules 1..11 # Looks like you failed 1 test of 11 Failed 1/11 subtests
    355. 355. %pg_prove -v -d try schema.sql schema.sql .. ok 1 - There should be the correct schemas not ok 2 - Schema biz should have the correct tables # Failed test 2: "Schema biz should have the correct tables" # Extra tables: # mallots # __test_table # Missing tables: # users # widgets ok 3 - Schema biz should have the correct views ok 4 - Schema biz should have the correct sequences ok 5 - Table biz.users should have the correct indexes ok 6 - Schema biz should have the correct functions ok 7 - There should be the correct users ok 8 - There should be the correct groups ok 9 - There should be the correct procedural languages ok 10 - Schema biz should have the correct operator classes ok 11 - Relation biz.users should have the correct rules 1..11 # Looks like you failed 1 test of 11 Failed 1/11 subtests
    356. 356. Schema Testing
    357. 357. Schema Testing Validate presence of objects
    358. 358. Schema Testing Validate presence of objects Validate object interfaces
    359. 359. Schema Testing Validate presence of objects Validate object interfaces Prevent others from changing schema
    360. 360. Schema Testing Validate presence of objects Validate object interfaces Prevent others from changing schema Maintain a consistent interface
    361. 361. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    362. 362. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    363. 363. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    364. 364. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    365. 365. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    366. 366. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    367. 367. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    368. 368. BEGIN; SET search_path TO public, tap; SELECT plan(13); SELECT has_table( 'users' ); SELECT has_pk( 'users' ); SELECT has_column( 'users', 'user_id' ); SELECT col_type_is( 'users', 'user_id', 'integer' ); SELECT col_not_null( 'users', 'user_id' ); SELECT col_is_pk( 'users', 'user_id' ); SELECT has_column( 'users', 'birthdate' ); SELECT col_type_is( 'users', 'birthdate', 'date' ); SELECT col_is_null( 'users', 'birthdate' ); SELECT has_column( 'users', 'state' ); SELECT col_type_is( 'users', 'state', 'text' ); SELECT col_not_null( 'users', 'state' ); SELECT col_default_is( 'users', 'state', 'active' ); SELECT * FROM finish(); ROLLBACK;
    369. 369. SELECT has_tablespace( 'indexspace', '/data/idxs' ); SELECT has_schema( 'biz' ); SELECT has_view( 'biz', 'list_users' ); SELECT has_sequence( 'biz', 'users_id_seq' ); SELECT has_type( 'biz', 'timezone' ); SELECT has_domain( 'biz', 'timezone' ); SELECT has_enum( 'biz', 'escalation' ); SELECT has_index( 'biz', 'users', 'idx_nick' ); SELECT has_trigger( 'biz', 'users', 'md5_pass' ); SELECT has_rule( 'biz', 'list_users', 'user_ins' ); SELECT has_function( 'biz', 'get_user_data' ); SELECT has_role( 'postgres' ); SELECT has_user( 'postgres' ); SELECT has_group( 'postgres' ); SELECT has_language( 'plpgsql' ); SELECT fk_ok( 'biz', 'widgets', 'user_id', 'biz', 'users', 'id' );
    370. 370. Function Testing Functions
    371. 371. Function Testing Functions SELECT function_lang_is( 'biz', 'get_user', 'sql' ); SELECT function_returns( 'biz', 'get_user', 'users' ); SELECT is_definer( 'biz', 'get_user_data' ); SELECT is_strict( 'biz', 'get_user_data' ); SELECT volatility_is( 'biz', 'get_user', 'volatile' ); SELECT is_aggregate( 'biz', 'array_accum' ); SELECT trigger_is( 'biz', 'users', 'md5_pass', 'biz', 'md5er' );
    372. 372. Utilities
    373. 373. Utilities SELECT CASE WHEN pgtap_version() < 0.17 THEN skip('No sequence assertions before pgTAP 0.17') ELSE has_sequence('my_big_seq') END; SELECT CASE WHEN pg_version_num() < 80100 THEN skip('throws_ok() not supported before 8.1') ELSE throws_ok( 'SELECT 1/0', 22012, 'div by zero' ) END;
    374. 374. Utilities SELECT CASE WHEN pgtap_version() < 0.17 THEN skip('No sequence assertions before pgTAP 0.17') ELSE has_sequence('my_big_seq') END; SELECT CASE WHEN pg_version_num() < 80100 THEN skip('throws_ok() not supported before 8.1') ELSE throws_ok( 'SELECT 1/0', 22012, 'div by zero' ) END;
    375. 375. Utilities SELECT CASE WHEN pgtap_version() < 0.17 THEN skip('No sequence assertions before pgTAP 0.17') ELSE has_sequence('my_big_seq') END; SELECT CASE WHEN pg_version_num() < 80100 THEN skip('throws_ok() not supported before 8.1') ELSE throws_ok( 'SELECT 1/0', 22012, 'div by zero' ) END;
    376. 376. Other Features and Topics
    377. 377. Other Features and Topics xUnit-Style testing
    378. 378. Other Features and Topics xUnit-Style testing Test-Driven development
    379. 379. Other Features and Topics xUnit-Style testing Test-Driven development Integration with Perl unit tests
    380. 380. Other Features and Topics xUnit-Style testing Test-Driven development Integration with Perl unit tests Integration with pg_regress
    381. 381. Other Features and Topics xUnit-Style testing Test-Driven development Integration with Perl unit tests Integration with pg_regress Negative assertions
    382. 382. Other Features and Topics xUnit-Style testing Test-Driven development Integration with Perl unit tests Integration with pg_regress Negative assertions Constraint assertions
    383. 383. Other Features and Topics xUnit-Style testing Test-Driven development Integration with Perl unit tests Integration with pg_regress Negative assertions Constraint assertions Roles and permissions assertions
    384. 384. Other Features and Topics xUnit-Style testing Test-Driven development Integration with Perl unit tests Integration with pg_regress Negative assertions Constraint assertions Roles and permissions assertions Lots more!
    385. 385. Thank You pgTAP Best Practices David E. Wheeler Kineticode, Inc. PostgreSQL Experts, Inc. PostgreSQL Conference West 2009

    ×