SlideShare uma empresa Scribd logo
1 de 84
Baixar para ler offline
Why you ever meta data you didn’t like:
Testing twisty little passages all alike.
Steven Lembark
Workhorse Computing
lemark@wrkhors.com
What is testing?
Smoke, white- & black-box, integration, regression...
Set up controlled environment.
See if software fails.
Lather, rinse repeat...
Controls include data, environment, handlers.
The usual way: Template tests
Write a test.
Make it work.
Copy it.
Edit it.
Copy it.
Edit it.
Copy...
“Red flags”
Cut + paste
Works until you find a bug...
Need a change...
Update 45 files.
Common result: A mess
Single directory.
Semi-random basenames.
Difficult to run in order.
First piece of metadata
Filesystem is powerful medicine.
Cures all sorts of problems.
Basenames
prove uses lexical order.
100-perlcritic.t
101-perltidy.t
102-pod.t
103-podt.t
10-init.t
200-player-TestRoo.t
201-TestRoo-Action.t
201-TestRoo-Actor.t
201-TestRoo-Adventure.t
201-TestRoo-Base.t
201-TestRoo-Item.t
201-TestRoo-Location.t
201-TestRoo-Player.t
202-TestClassMoose.t
20-player.t
300-black-hole.t
60-command.t
Basenames
prove uses lexical order.
Might not be what you
want.
100-perlcritic.t
101-perltidy.t
102-pod.t
103-podt.t
10-init.t
200-player-TestRoo.t
201-TestRoo-Action.t
201-TestRoo-Actor.t
201-TestRoo-Adventure.t
201-TestRoo-Base.t
201-TestRoo-Item.t
201-TestRoo-Location.t
201-TestRoo-Player.t
202-TestClassMoose.t
20-player.t
300-black-hole.t
60-command.t
Basenames
prove uses lexical order.
Might not be what you
want.
Use consistent names.
010-init.t
020-player.t
060-command.t
100-perlcritic.t
101-perltidy.t
102-pod.t
103-podt.t
200-player-TestRoo.t
201-TestRoo-Action.t
201-TestRoo-Actor.t
201-TestRoo-Adventure.t
201-TestRoo-Base.t
201-TestRoo-Item.t
201-TestRoo-Location.t
201-TestRoo-Player.t
202-TestClassMoose.t
300-black-hole.t
Directories
Need every test every time?
010-init.t
020-player.t
060-command.t
100-perlcritic.t
101-perltidy.t
102-pod.t
103-podt.t
200-player-TestRoo.t
201-TestRoo-Action.t
201-TestRoo-Actor.t
201-TestRoo-Adventure.t
201-TestRoo-Base.t
201-TestRoo-Item.t
201-TestRoo-Location.t
201-TestRoo-Player.t
202-TestClassMoose.t
300-black-hole.t
Directories
Need every test every time?
What about:
Quick tests for check-in.
Complete for release.
010-init.t
020-player.t
060-command.t
100-perlcritic.t
101-perltidy.t
102-pod.t
103-podt.t
200-player-TestRoo.t
201-TestRoo-Action.t
201-TestRoo-Actor.t
201-TestRoo-Adventure.t
201-TestRoo-Base.t
201-TestRoo-Item.t
201-TestRoo-Location.t
201-TestRoo-Player.t
202-TestClassMoose.t
300-black-hole.t
Directories
Need every test every time?
What about:
prove && commit;
prove -r && release;
010-init.t
020-player.t
060-command.t
100-perlcritic.t
101-perltidy.t
102-pod.t
103-podt.t
200-Modules
300-Missions
Directories
Need every test every time?
What about:
prove && commit;
prove -r && release;
01-init.t
02-player.t
06-command.t
10-perlcritic.t
11-perltidy.t
12-pod.t
13-podt.t
20-Modules
30-Missions
Directories
Need every test every time?
What about:
prove && commit;
prove -r && release;
01-init.t
02-player.t
06-command.t
10-perlcritic.t
11-perltidy.t
12-pod.t
13-podt.t
20-Modules
30-Missions
Directories
Need every test every time?
Baseline & config checks.
prove t/0*t;
01-init.t
02-player.t
06-command.t
10-perlcritic.t
11-perltidy.t
12-pod.t
13-podt.t
20-Modules
30-Missions
Directories
Need every test every time?
Simple integration tests:
prove -v t/1*t;
01-init.t
02-player.t
06-command.t
10-perlcritic.t
11-perltidy.t
12-pod.t
13-podt.t
20-Modules
30-Missions
Tests don’t need to be stupid.
Adding a little logic avoids copying.
Lazy: Write once, recycle in place.
Choose your mission
Defines the map, monsters, goal.
The mission files start with:
my $pkg = 'Adventure';
my $path = 't/etc/EmptyMap00.yaml';
Choose your mission
Defines the map, monsters, goal.
One set of tests starts with:
Same tests for any config file.
my $pkg = 'Adventure';
my $path = 't/etc/EmptyMap00.yaml';
Choose your mission
Defines the map, monsters, goal.
Don’t copy the file:
my $pkg = 'Adventure';
my $base = basename $0, ‘.t’;
my $path = “t/etc/$base.yaml”;
Choose your mission
Defines the map, monsters, goal.
Don’t copy the file:
Symlink them all to “./bin/01-mission_t”.
my $pkg = 'Adventure';
my $base = basename $0, ‘.t’;
my $path = “t/etc/$base.yaml”;
Choose your mission
cd $(dirname $0)/../20-Missions;
for i in ../etc/*-mission.yaml;
do
base=$(basename $i .yaml);
ln -fs ../bin/01-mission_t ./01-$base.t;
done
One “test” for many configs:
Generic tests: well-formed Perl
“use_ok” is unfairly maligned.
It does something quite useful.
Better off if all modules pass it.
Generic tests: well-formed Perl
“use_ok” is unfairly maligned.
It does something quite useful.
Better off if all modules pass it.
And have a working package name.
With a version.
Generic tests: well-formed Perl
use Test::More;
use_ok ‘Frobnicate’;
can_ok Frobnicate => ‘VERSION’;
ok Frobnicate->VERSION,
“Frobnicate has a version”;
done_testing;
__END__
Generic tests: well-formed Perl
use Test::More;
use_ok ‘Frobnicate’;
can_ok Frobnicate => ‘VERSION’;
ok Frobnicate->VERSION,
“Frobnicate has a version”;
done_testing;
__END__
Generic tests: well-formed Perl
use Test::More;
my $package= ‘Frobnicate’;
use_ok $package;
can_ok $package => ‘VERSION’;
ok $frobnicate->VERSION,
“$package has a version”;
done_testing;
Generic tests: well-formed Perl
my $package= ‘Frobnicate’;
Generic tests: well-formed Perl
my $base = basename $0, ‘.t’;
my @partz = split /W+/, $base;
my $package
= join ‘::’, @partz[ 1 .. $#partz ];
Generic tests: well-formed Perl
ln -fs ../bin/01-generic_t 
./01-Acme-Eyedrops.t;
Test them all
cd $(dirname $0)/..;
rm -f 01*.t;
find .. -name $glob |
perl -n 
-E 'state $path = ( glob "./bin/01-*_t" )[0];' 
-E 'chomp;' 
-E 'my @a = split m{[/]}, substr $_, 3;' 
-E 'my $b = join "-", @a;' 
-E 'symlink $path => "01-$b.t" or warn' ;
Testing groups of files
Runs same test on all modules:
prove 10-*.t ;
Test class & children:
prove *-Parent-*.t;
find t -name $glob | xargs prove;
Combine with commits
Git tags mark prove success.
Combine prove with git tags to track progress:
prove && git tag …
Merge tags into main branch for Q/A.
Use “prove -r” in master for Q/A pass.
Generic tests: well formed configs.
Ever fat-finger some JSON?
Leave out an XML tag?
Mis-quote an .ini?
Generic tests: config files.
Ever fat-finger some JSON?
Leave out an XML tag?
Mis-quote an .ini?
Then waste debugging code to find it?
Generic tests: config files
To the rescue: Config::Any.
If its read-able, we can check it.
At least for readabiliy...
Generic tests: config files
Same basic trick: symlink a reader.
my $base = basename $0;
my @partz= split /W+/, $base;
my $test = join ‘~’ => ‘01’, @partz;
symlink ‘../bin/00-config_t’ =>
$test . ‘.t’;
#!/bin/bash
cd $(dirname $0)/..; # run from ./t/bin
rm -f 0*.t; # remove generic tests
i='-1';
for glob in '*.yaml' '*.pm' # test config & modules
do
export j="0$((++i))";
echo "Pass: $j";
ls ./bin/$j-*_t;
find .. -name $glob |
perl -n 
-E 'state $path = ( glob "./bin/$ENV{j}-*_t" )[0];' 
-E 'chomp;' 
-E 'my @a = split m{[/]}, substr $_, 3;' 
-E 'my $b = join "-", @a;' 
-E 'symlink $path => "$ENV{j}-$b.t" or warn' ;
done
exit 0;
Re-duce, Re-use, Re-cycle
Tests only depend on “.pm”.
Re-use on multiple directories.
Across projects.
Metadata: ./t is for testing
Ever test a production database?
Destructively?
Ouch...
Metadata: test configs are in ./t/etc.
Metadata: ./t is for testing
# tests find ./t/lib/Foo/Config.pm
# ./bin files find ./lib/Foo/Config.pm
use FindBin::libs;
use Foo::Config;
Metadata: ./t is for testing
# tests prefer ./t/etc
use FindBin::libs qw( base=etc export );
my $base = ‘Database.config.yaml’;
my $found
= first {-e “$_/$base” } @etc
or die “Oops... no database config.n”;
my $path = “$found/$base”;
Looking inside yourself
Or, at least, inside of Perl.
Overloads.
Closures.
Non-OO Polymorphism.
Dispatch via scalar.
Say you want to test Madness for a Method.
$madness->method( … );
Dispatch via scalar.
Say you want to test Madness for a Method.
$madness->$method( … ); # Perl5
$method can be text or a subref...
Aside: Dispatch in Perl6
my $code = sub { … };
$madness.$code;
$madness.$code( @argz );
my $name = ‘subname’;
$madness.”$name”();
$madness.”$name”( @argz );
Testing many methods
Iterate an object over many methods:
$object->$_( @argz )
for @methodz;
Example: Object::Exercise
my @plan =
(
[
[ method => ( ‘a’, ‘b’ ) ],
[ ‘Expected Return Value’ ],
[ ‘Your message here’ ],
],
Example: Object::Exercise
my @plan =
(
[
[ method => ( ‘a’, ‘b’ ) ],
[ ‘Expected Return Value’ ],
[ ‘Your message here’ ],
],
Example: Object::Exercise
use Object::Exercise;
my @plan = ( [ … ], [ … ], … );
$madness
->new( … )
->$exercise( @plan );
Example: Object::Exercise
use Object::Exercise;
my @plan = generate_plan( … );
$madness
->new( … )
->$exercise( @plan );
Example: Object::Exercise
my @plan = generate_plan( … );
Generate plan can read a YAML file...
Query a database...
Read a symlink...
Multiple tests in YAML
---
-
- - method
- a
- b
- - Expected Return Value
- - Your Message Here
-
- - frobnicate
- ...
Testing system failures
Check for file-read failures.
Bad way: Hack the filesystem.
Beter way: Hack Perl CORE.
All politics is local
So are values.
“local” provides scoped values.
local $ = “n”;
local *STDOUT = $fh;
Perl Testers Notebook
Great book, even with the fake coffee stains.
One nice technique described in detail:
Hacking CORE.
Say you want to open to fail.
Hack open???
sub
{
# see Perl Testing Notebook
local *CORE::open
= sub { die “No such file.n” };
$madness->$method( @_ );
}
Fail on one specific path
sub fail_on_open
{
my $pkg = shift;
my $path = shift;
my $open = $pkg->can( ‘open_config’ );
sub
{
$_[1] eq $path
and die “Failed open: ‘$path’n”;
goto &$open;
}
}
Wrap a method to fail on a specific file
my @plan
= map
{
my $sub = fail_on_open $pkg, $_;
[
[ $sub, “$_” ],undef,[ “Fail: $_” ]
]
}
glob “/etc/frobnicate/*.config.*”;
Testing runt reads
.ini or data files may not have bookends.
Lacking a closing marker, can you detect runts?
Bad test: Write hacked files to temp dir’s.
Better test: Hack your reader.
Dispatch a partial read
my $path = shift;
sub
{
$_[1] eq $path or goto &$wrapped;
my $data = &$wrapped;
substr $data, 0, rand length $data
}
my $method = ‘do_something’;
my @plan
= map
{
my $path = $_;
my $runt = gen_runt_read $path;
my $ref = qualify_to_ref read_cfg => $pkg;
my $sub
= sub
{
local *{ $ref } = $runt;
$object->$method( $path )
};
[
[ $sub, $path ], undef, [ “Failed read: ‘$path’” ]
]
}
glob $glob;
$object->$exercise( @plan ); # verify failing on each conf
Checking mods
Overload stat to return zero size, hacked mods.
Force fail on -s, -r checks for data files.
Return non-existant or zero UID, GID.
Mapped tests
Good: One test file, one test result.
Bad: Have to test them all each time.
Alternatives:
Symlink individual tests.
Break glob-lists into smaller pieces.
Aside: “Testable” code.
Monolithic code is harder to test.
Testing a find-and-check-and-validate-and-open-
and-read-and-close-and-evaluate-and-install-values-
and-use-values-and-return is hard.
Faking an open is relatively easy.
So is faking a read.
Un-testable code is less maintainable.
Adventure: Your mission...
Given a data file, play the game.
Twisty little passages, nasty trolls, you name it.
Sanity checking size
Generic wrapper: call a method, check size of
object.
Same basic wrapper:
Store size.
Call something.
Re-examine size.
---
name: Empty Map 00
namespace : EmptyMap00
locations:
blackhole:
name: BlackHole
description : You are standing in a small Black Hole.
exits :
Out : blackhole
items: {}
player:
location : blackhole
items : {}
---
name: Empty Map 00
namespace : EmptyMap00
locations:
blackhole:
name: BlackHole
description : You are standing in a small Black Hole.
exits :
Out : blackhole
items: {}
player:
location : blackhole
items : {}
Entering a black hole
use FindBin::libs qw(base=etc export scalar);
my $madness = ‘Adventure’;
use_ok $madness;
$madness->init(“$etc/blackhole.yaml);
my $player = $madness->player;
is_ok ‘blackhole’, $player->location;
$player->location_object
->use_exit('blackhole');
is_ok ‘blackhole’, $player->location;
Look for memory leaks
ok $player->move( blackhole ), “Can move out”
for 1 .. 1_000_000;
Look for memory leaks
ok $player->move( out ), “Can move out”
for 1 .. 1_000_000;
Downside: a million OK’s.
Avoid a million OK’s.
my $expect = ‘out’;
my $found= ‘’;
my $i;
for $i ( 1 .. 1_000_000 )
{
$player->move( $expect );
$found = $player->location;
$expect eq $found or last;
}
is $found, $expect, “’$found’-‘$expect’ at $i”;
How big are you?
Memory footprint:
sum_size
{
sum map { size $_ } @_
}
Yes, guys, size() does matter
my $loc = $player->location_object;
my $prior = 1.1*sum_size $madness, $player;
$loc->use_exit('blackhole')
for( 1 .. 1_000_000 );
my $after = sum_size $madness, $player;
ok $after < $prior, “$after < $prior”;
Generic Tests
Init the game with a mission file.
Check the initial location.
Write a black-hole file with 1 .. N stages.
Check that the size doesn’t grow.
my $base = basename $0, ‘.t’;
my $limit = ( split / W /x, $base )[ -1 ];
my $path= make_daisy_chain_map $limit;
Adventure->init( $path );
my $player = Adventure->player;
my $loc = $player->location_object;
my $prior = 1.1 * size $player;
for my $i ( 1 .. $limit )
{
my $next = ‘room_’ . $i;
$loc->use_exit( $next );
$next eq $loc->location or last;
my $after = size $player;
$prior > $after or last;
}
Playing with the web
Ever have test a web app?
But didn’t have a “back end”?
You are doing it wrong!
Selenium Sandwich
Sandwich the browser between tasty layers of Perl:
use Plack;
use Selenium;
Metadata-driven selenium testing
Four structs define an iteration:
[
[ DOM contents ],
[ Expected values ],
[ return struct ],
[ result DOM ]
]
Failing successfully
Return the HTTP failure code:
[
[ DOM contents ],
[ Expected values ],
[ 404, “Oops...”, ],
[ result DOM ]
]
Summary
Avoid “red flags”.
Use data to drive tests.
Metadata to generate the data.
Abstract your tests.
Bedside reading
Object::Exercise
Selenium Sandwich
Getting Testy with Perl
https://www.slideshare.net/lembark
Bedside reading
Adventure:
git@github.com:rizen/Adventure.git

Mais conteúdo relacionado

Mais procurados

Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Workhorse Computing
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Workhorse Computing
 
Building and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning CBuilding and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning CDavid Wheeler
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Workhorse Computing
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 OverlordsI, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlordsheumann
 
Melhorando sua API com DSLs
Melhorando sua API com DSLsMelhorando sua API com DSLs
Melhorando sua API com DSLsAugusto Pascutti
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model Perforce
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationBarely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationAttila Balazs
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know Aboutjoshua.mcadams
 
Puppet Camp Paris 2015: Power of Puppet 4 (Beginner)
Puppet Camp Paris 2015: Power of Puppet 4 (Beginner) Puppet Camp Paris 2015: Power of Puppet 4 (Beginner)
Puppet Camp Paris 2015: Power of Puppet 4 (Beginner) Puppet
 
The Joy of Smartmatch
The Joy of SmartmatchThe Joy of Smartmatch
The Joy of SmartmatchAndrew Shitov
 

Mais procurados (20)

Short Introduction To "perl -d"
Short Introduction To "perl -d"Short Introduction To "perl -d"
Short Introduction To "perl -d"
 
Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
Smoking docker
Smoking dockerSmoking docker
Smoking docker
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
 
Getting testy with Perl
Getting testy with PerlGetting testy with Perl
Getting testy with Perl
 
Building and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning CBuilding and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning C
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 OverlordsI, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlords
 
Melhorando sua API com DSLs
Melhorando sua API com DSLsMelhorando sua API com DSLs
Melhorando sua API com DSLs
 
Perl6 in-production
Perl6 in-productionPerl6 in-production
Perl6 in-production
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model
 
Perl6 grammars
Perl6 grammarsPerl6 grammars
Perl6 grammars
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl PresentationBarely Legal Xxx Perl Presentation
Barely Legal Xxx Perl Presentation
 
Utility Modules That You Should Know About
Utility Modules That You Should Know AboutUtility Modules That You Should Know About
Utility Modules That You Should Know About
 
Puppet Camp Paris 2015: Power of Puppet 4 (Beginner)
Puppet Camp Paris 2015: Power of Puppet 4 (Beginner) Puppet Camp Paris 2015: Power of Puppet 4 (Beginner)
Puppet Camp Paris 2015: Power of Puppet 4 (Beginner)
 
Ruby 2.0
Ruby 2.0Ruby 2.0
Ruby 2.0
 
The Joy of Smartmatch
The Joy of SmartmatchThe Joy of Smartmatch
The Joy of Smartmatch
 

Semelhante a Metadata-driven Testing

Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl TechniquesDave Cross
 
More tips n tricks
More tips n tricksMore tips n tricks
More tips n tricksbcoca
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring QualityKent Cowgill
 
Isolated development in python
Isolated development in pythonIsolated development in python
Isolated development in pythonAndrés J. Díaz
 
The Essential Perl Hacker's Toolkit
The Essential Perl Hacker's ToolkitThe Essential Perl Hacker's Toolkit
The Essential Perl Hacker's ToolkitStephen Scaffidi
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passageErik Rose
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
Learning Puppet basic thing
Learning Puppet basic thing Learning Puppet basic thing
Learning Puppet basic thing DaeHyung Lee
 
Unit testing presentation
Unit testing presentationUnit testing presentation
Unit testing presentationArthur Freyman
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentationThanh Robi
 
Testing With Test::Class
Testing With Test::ClassTesting With Test::Class
Testing With Test::ClassCurtis Poe
 
Moose: Perl Objects
Moose: Perl ObjectsMoose: Perl Objects
Moose: Perl ObjectsLambert Lum
 

Semelhante a Metadata-driven Testing (20)

Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
More tips n tricks
More tips n tricksMore tips n tricks
More tips n tricks
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring Quality
 
Isolated development in python
Isolated development in pythonIsolated development in python
Isolated development in python
 
Getting Testy With Perl6
Getting Testy With Perl6Getting Testy With Perl6
Getting Testy With Perl6
 
The Essential Perl Hacker's Toolkit
The Essential Perl Hacker's ToolkitThe Essential Perl Hacker's Toolkit
The Essential Perl Hacker's Toolkit
 
C# to python
C# to pythonC# to python
C# to python
 
Five
FiveFive
Five
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passage
 
Cucumber testing
Cucumber testingCucumber testing
Cucumber testing
 
Cucumber testing
Cucumber testingCucumber testing
Cucumber testing
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Bioinformatics p5-bioperlv2014
Bioinformatics p5-bioperlv2014Bioinformatics p5-bioperlv2014
Bioinformatics p5-bioperlv2014
 
Learning Puppet basic thing
Learning Puppet basic thing Learning Puppet basic thing
Learning Puppet basic thing
 
Python basic
Python basicPython basic
Python basic
 
Unit testing presentation
Unit testing presentationUnit testing presentation
Unit testing presentation
 
PHPUnit best practices presentation
PHPUnit best practices presentationPHPUnit best practices presentation
PHPUnit best practices presentation
 
Testing With Test::Class
Testing With Test::ClassTesting With Test::Class
Testing With Test::Class
 
Moose: Perl Objects
Moose: Perl ObjectsMoose: Perl Objects
Moose: Perl Objects
 

Mais de Workhorse Computing

Mais de Workhorse Computing (17)

Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility ModulesWheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility Modules
 
mro-every.pdf
mro-every.pdfmro-every.pdf
mro-every.pdf
 
Paranormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add UpParanormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add Up
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlGenerating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in Posgresql
 
Effective Benchmarks
Effective BenchmarksEffective Benchmarks
Effective Benchmarks
 
The W-curve and its application.
The W-curve and its application.The W-curve and its application.
The W-curve and its application.
 
Neatly folding-a-tree
Neatly folding-a-treeNeatly folding-a-tree
Neatly folding-a-tree
 
Light my-fuse
Light my-fuseLight my-fuse
Light my-fuse
 
Paranormal stats
Paranormal statsParanormal stats
Paranormal stats
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
 
Putting some "logic" in LVM.
Putting some "logic" in LVM.Putting some "logic" in LVM.
Putting some "logic" in LVM.
 
Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.
 
Selenium sandwich-2
Selenium sandwich-2Selenium sandwich-2
Selenium sandwich-2
 
Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium
 
Docker perl build
Docker perl buildDocker perl build
Docker perl build
 
Designing net-aws-glacier
Designing net-aws-glacierDesigning net-aws-glacier
Designing net-aws-glacier
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and Benchmarks
 

Último

TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 

Último (20)

TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 

Metadata-driven Testing

  • 1. Why you ever meta data you didn’t like: Testing twisty little passages all alike. Steven Lembark Workhorse Computing lemark@wrkhors.com
  • 2. What is testing? Smoke, white- & black-box, integration, regression... Set up controlled environment. See if software fails. Lather, rinse repeat... Controls include data, environment, handlers.
  • 3. The usual way: Template tests Write a test. Make it work. Copy it. Edit it. Copy it. Edit it. Copy...
  • 4. “Red flags” Cut + paste Works until you find a bug... Need a change... Update 45 files.
  • 5. Common result: A mess Single directory. Semi-random basenames. Difficult to run in order.
  • 6. First piece of metadata Filesystem is powerful medicine. Cures all sorts of problems.
  • 7. Basenames prove uses lexical order. 100-perlcritic.t 101-perltidy.t 102-pod.t 103-podt.t 10-init.t 200-player-TestRoo.t 201-TestRoo-Action.t 201-TestRoo-Actor.t 201-TestRoo-Adventure.t 201-TestRoo-Base.t 201-TestRoo-Item.t 201-TestRoo-Location.t 201-TestRoo-Player.t 202-TestClassMoose.t 20-player.t 300-black-hole.t 60-command.t
  • 8. Basenames prove uses lexical order. Might not be what you want. 100-perlcritic.t 101-perltidy.t 102-pod.t 103-podt.t 10-init.t 200-player-TestRoo.t 201-TestRoo-Action.t 201-TestRoo-Actor.t 201-TestRoo-Adventure.t 201-TestRoo-Base.t 201-TestRoo-Item.t 201-TestRoo-Location.t 201-TestRoo-Player.t 202-TestClassMoose.t 20-player.t 300-black-hole.t 60-command.t
  • 9. Basenames prove uses lexical order. Might not be what you want. Use consistent names. 010-init.t 020-player.t 060-command.t 100-perlcritic.t 101-perltidy.t 102-pod.t 103-podt.t 200-player-TestRoo.t 201-TestRoo-Action.t 201-TestRoo-Actor.t 201-TestRoo-Adventure.t 201-TestRoo-Base.t 201-TestRoo-Item.t 201-TestRoo-Location.t 201-TestRoo-Player.t 202-TestClassMoose.t 300-black-hole.t
  • 10. Directories Need every test every time? 010-init.t 020-player.t 060-command.t 100-perlcritic.t 101-perltidy.t 102-pod.t 103-podt.t 200-player-TestRoo.t 201-TestRoo-Action.t 201-TestRoo-Actor.t 201-TestRoo-Adventure.t 201-TestRoo-Base.t 201-TestRoo-Item.t 201-TestRoo-Location.t 201-TestRoo-Player.t 202-TestClassMoose.t 300-black-hole.t
  • 11. Directories Need every test every time? What about: Quick tests for check-in. Complete for release. 010-init.t 020-player.t 060-command.t 100-perlcritic.t 101-perltidy.t 102-pod.t 103-podt.t 200-player-TestRoo.t 201-TestRoo-Action.t 201-TestRoo-Actor.t 201-TestRoo-Adventure.t 201-TestRoo-Base.t 201-TestRoo-Item.t 201-TestRoo-Location.t 201-TestRoo-Player.t 202-TestClassMoose.t 300-black-hole.t
  • 12. Directories Need every test every time? What about: prove && commit; prove -r && release; 010-init.t 020-player.t 060-command.t 100-perlcritic.t 101-perltidy.t 102-pod.t 103-podt.t 200-Modules 300-Missions
  • 13. Directories Need every test every time? What about: prove && commit; prove -r && release; 01-init.t 02-player.t 06-command.t 10-perlcritic.t 11-perltidy.t 12-pod.t 13-podt.t 20-Modules 30-Missions
  • 14. Directories Need every test every time? What about: prove && commit; prove -r && release; 01-init.t 02-player.t 06-command.t 10-perlcritic.t 11-perltidy.t 12-pod.t 13-podt.t 20-Modules 30-Missions
  • 15. Directories Need every test every time? Baseline & config checks. prove t/0*t; 01-init.t 02-player.t 06-command.t 10-perlcritic.t 11-perltidy.t 12-pod.t 13-podt.t 20-Modules 30-Missions
  • 16. Directories Need every test every time? Simple integration tests: prove -v t/1*t; 01-init.t 02-player.t 06-command.t 10-perlcritic.t 11-perltidy.t 12-pod.t 13-podt.t 20-Modules 30-Missions
  • 17. Tests don’t need to be stupid. Adding a little logic avoids copying. Lazy: Write once, recycle in place.
  • 18. Choose your mission Defines the map, monsters, goal. The mission files start with: my $pkg = 'Adventure'; my $path = 't/etc/EmptyMap00.yaml';
  • 19. Choose your mission Defines the map, monsters, goal. One set of tests starts with: Same tests for any config file. my $pkg = 'Adventure'; my $path = 't/etc/EmptyMap00.yaml';
  • 20. Choose your mission Defines the map, monsters, goal. Don’t copy the file: my $pkg = 'Adventure'; my $base = basename $0, ‘.t’; my $path = “t/etc/$base.yaml”;
  • 21. Choose your mission Defines the map, monsters, goal. Don’t copy the file: Symlink them all to “./bin/01-mission_t”. my $pkg = 'Adventure'; my $base = basename $0, ‘.t’; my $path = “t/etc/$base.yaml”;
  • 22. Choose your mission cd $(dirname $0)/../20-Missions; for i in ../etc/*-mission.yaml; do base=$(basename $i .yaml); ln -fs ../bin/01-mission_t ./01-$base.t; done One “test” for many configs:
  • 23. Generic tests: well-formed Perl “use_ok” is unfairly maligned. It does something quite useful. Better off if all modules pass it.
  • 24. Generic tests: well-formed Perl “use_ok” is unfairly maligned. It does something quite useful. Better off if all modules pass it. And have a working package name. With a version.
  • 25. Generic tests: well-formed Perl use Test::More; use_ok ‘Frobnicate’; can_ok Frobnicate => ‘VERSION’; ok Frobnicate->VERSION, “Frobnicate has a version”; done_testing; __END__
  • 26. Generic tests: well-formed Perl use Test::More; use_ok ‘Frobnicate’; can_ok Frobnicate => ‘VERSION’; ok Frobnicate->VERSION, “Frobnicate has a version”; done_testing; __END__
  • 27. Generic tests: well-formed Perl use Test::More; my $package= ‘Frobnicate’; use_ok $package; can_ok $package => ‘VERSION’; ok $frobnicate->VERSION, “$package has a version”; done_testing;
  • 28. Generic tests: well-formed Perl my $package= ‘Frobnicate’;
  • 29. Generic tests: well-formed Perl my $base = basename $0, ‘.t’; my @partz = split /W+/, $base; my $package = join ‘::’, @partz[ 1 .. $#partz ];
  • 30. Generic tests: well-formed Perl ln -fs ../bin/01-generic_t ./01-Acme-Eyedrops.t;
  • 31. Test them all cd $(dirname $0)/..; rm -f 01*.t; find .. -name $glob | perl -n -E 'state $path = ( glob "./bin/01-*_t" )[0];' -E 'chomp;' -E 'my @a = split m{[/]}, substr $_, 3;' -E 'my $b = join "-", @a;' -E 'symlink $path => "01-$b.t" or warn' ;
  • 32. Testing groups of files Runs same test on all modules: prove 10-*.t ; Test class & children: prove *-Parent-*.t; find t -name $glob | xargs prove;
  • 33. Combine with commits Git tags mark prove success. Combine prove with git tags to track progress: prove && git tag … Merge tags into main branch for Q/A. Use “prove -r” in master for Q/A pass.
  • 34. Generic tests: well formed configs. Ever fat-finger some JSON? Leave out an XML tag? Mis-quote an .ini?
  • 35. Generic tests: config files. Ever fat-finger some JSON? Leave out an XML tag? Mis-quote an .ini? Then waste debugging code to find it?
  • 36. Generic tests: config files To the rescue: Config::Any. If its read-able, we can check it. At least for readabiliy...
  • 37. Generic tests: config files Same basic trick: symlink a reader. my $base = basename $0; my @partz= split /W+/, $base; my $test = join ‘~’ => ‘01’, @partz; symlink ‘../bin/00-config_t’ => $test . ‘.t’;
  • 38. #!/bin/bash cd $(dirname $0)/..; # run from ./t/bin rm -f 0*.t; # remove generic tests i='-1'; for glob in '*.yaml' '*.pm' # test config & modules do export j="0$((++i))"; echo "Pass: $j"; ls ./bin/$j-*_t; find .. -name $glob | perl -n -E 'state $path = ( glob "./bin/$ENV{j}-*_t" )[0];' -E 'chomp;' -E 'my @a = split m{[/]}, substr $_, 3;' -E 'my $b = join "-", @a;' -E 'symlink $path => "$ENV{j}-$b.t" or warn' ; done exit 0;
  • 39. Re-duce, Re-use, Re-cycle Tests only depend on “.pm”. Re-use on multiple directories. Across projects.
  • 40. Metadata: ./t is for testing Ever test a production database? Destructively? Ouch... Metadata: test configs are in ./t/etc.
  • 41. Metadata: ./t is for testing # tests find ./t/lib/Foo/Config.pm # ./bin files find ./lib/Foo/Config.pm use FindBin::libs; use Foo::Config;
  • 42. Metadata: ./t is for testing # tests prefer ./t/etc use FindBin::libs qw( base=etc export ); my $base = ‘Database.config.yaml’; my $found = first {-e “$_/$base” } @etc or die “Oops... no database config.n”; my $path = “$found/$base”;
  • 43. Looking inside yourself Or, at least, inside of Perl. Overloads. Closures. Non-OO Polymorphism.
  • 44. Dispatch via scalar. Say you want to test Madness for a Method. $madness->method( … );
  • 45. Dispatch via scalar. Say you want to test Madness for a Method. $madness->$method( … ); # Perl5 $method can be text or a subref...
  • 46. Aside: Dispatch in Perl6 my $code = sub { … }; $madness.$code; $madness.$code( @argz ); my $name = ‘subname’; $madness.”$name”(); $madness.”$name”( @argz );
  • 47. Testing many methods Iterate an object over many methods: $object->$_( @argz ) for @methodz;
  • 48. Example: Object::Exercise my @plan = ( [ [ method => ( ‘a’, ‘b’ ) ], [ ‘Expected Return Value’ ], [ ‘Your message here’ ], ],
  • 49. Example: Object::Exercise my @plan = ( [ [ method => ( ‘a’, ‘b’ ) ], [ ‘Expected Return Value’ ], [ ‘Your message here’ ], ],
  • 50. Example: Object::Exercise use Object::Exercise; my @plan = ( [ … ], [ … ], … ); $madness ->new( … ) ->$exercise( @plan );
  • 51. Example: Object::Exercise use Object::Exercise; my @plan = generate_plan( … ); $madness ->new( … ) ->$exercise( @plan );
  • 52. Example: Object::Exercise my @plan = generate_plan( … ); Generate plan can read a YAML file... Query a database... Read a symlink...
  • 53. Multiple tests in YAML --- - - - method - a - b - - Expected Return Value - - Your Message Here - - - frobnicate - ...
  • 54. Testing system failures Check for file-read failures. Bad way: Hack the filesystem. Beter way: Hack Perl CORE.
  • 55. All politics is local So are values. “local” provides scoped values. local $ = “n”; local *STDOUT = $fh;
  • 56. Perl Testers Notebook Great book, even with the fake coffee stains. One nice technique described in detail: Hacking CORE. Say you want to open to fail.
  • 57. Hack open??? sub { # see Perl Testing Notebook local *CORE::open = sub { die “No such file.n” }; $madness->$method( @_ ); }
  • 58. Fail on one specific path sub fail_on_open { my $pkg = shift; my $path = shift; my $open = $pkg->can( ‘open_config’ ); sub { $_[1] eq $path and die “Failed open: ‘$path’n”; goto &$open; } }
  • 59. Wrap a method to fail on a specific file my @plan = map { my $sub = fail_on_open $pkg, $_; [ [ $sub, “$_” ],undef,[ “Fail: $_” ] ] } glob “/etc/frobnicate/*.config.*”;
  • 60. Testing runt reads .ini or data files may not have bookends. Lacking a closing marker, can you detect runts? Bad test: Write hacked files to temp dir’s. Better test: Hack your reader.
  • 61. Dispatch a partial read my $path = shift; sub { $_[1] eq $path or goto &$wrapped; my $data = &$wrapped; substr $data, 0, rand length $data }
  • 62. my $method = ‘do_something’; my @plan = map { my $path = $_; my $runt = gen_runt_read $path; my $ref = qualify_to_ref read_cfg => $pkg; my $sub = sub { local *{ $ref } = $runt; $object->$method( $path ) }; [ [ $sub, $path ], undef, [ “Failed read: ‘$path’” ] ] } glob $glob; $object->$exercise( @plan ); # verify failing on each conf
  • 63. Checking mods Overload stat to return zero size, hacked mods. Force fail on -s, -r checks for data files. Return non-existant or zero UID, GID.
  • 64. Mapped tests Good: One test file, one test result. Bad: Have to test them all each time. Alternatives: Symlink individual tests. Break glob-lists into smaller pieces.
  • 65. Aside: “Testable” code. Monolithic code is harder to test. Testing a find-and-check-and-validate-and-open- and-read-and-close-and-evaluate-and-install-values- and-use-values-and-return is hard. Faking an open is relatively easy. So is faking a read. Un-testable code is less maintainable.
  • 66. Adventure: Your mission... Given a data file, play the game. Twisty little passages, nasty trolls, you name it.
  • 67. Sanity checking size Generic wrapper: call a method, check size of object. Same basic wrapper: Store size. Call something. Re-examine size.
  • 68. --- name: Empty Map 00 namespace : EmptyMap00 locations: blackhole: name: BlackHole description : You are standing in a small Black Hole. exits : Out : blackhole items: {} player: location : blackhole items : {}
  • 69. --- name: Empty Map 00 namespace : EmptyMap00 locations: blackhole: name: BlackHole description : You are standing in a small Black Hole. exits : Out : blackhole items: {} player: location : blackhole items : {}
  • 70. Entering a black hole use FindBin::libs qw(base=etc export scalar); my $madness = ‘Adventure’; use_ok $madness; $madness->init(“$etc/blackhole.yaml); my $player = $madness->player; is_ok ‘blackhole’, $player->location; $player->location_object ->use_exit('blackhole'); is_ok ‘blackhole’, $player->location;
  • 71. Look for memory leaks ok $player->move( blackhole ), “Can move out” for 1 .. 1_000_000;
  • 72. Look for memory leaks ok $player->move( out ), “Can move out” for 1 .. 1_000_000; Downside: a million OK’s.
  • 73. Avoid a million OK’s. my $expect = ‘out’; my $found= ‘’; my $i; for $i ( 1 .. 1_000_000 ) { $player->move( $expect ); $found = $player->location; $expect eq $found or last; } is $found, $expect, “’$found’-‘$expect’ at $i”;
  • 74. How big are you? Memory footprint: sum_size { sum map { size $_ } @_ }
  • 75. Yes, guys, size() does matter my $loc = $player->location_object; my $prior = 1.1*sum_size $madness, $player; $loc->use_exit('blackhole') for( 1 .. 1_000_000 ); my $after = sum_size $madness, $player; ok $after < $prior, “$after < $prior”;
  • 76. Generic Tests Init the game with a mission file. Check the initial location. Write a black-hole file with 1 .. N stages. Check that the size doesn’t grow.
  • 77. my $base = basename $0, ‘.t’; my $limit = ( split / W /x, $base )[ -1 ]; my $path= make_daisy_chain_map $limit; Adventure->init( $path ); my $player = Adventure->player; my $loc = $player->location_object; my $prior = 1.1 * size $player; for my $i ( 1 .. $limit ) { my $next = ‘room_’ . $i; $loc->use_exit( $next ); $next eq $loc->location or last; my $after = size $player; $prior > $after or last; }
  • 78. Playing with the web Ever have test a web app? But didn’t have a “back end”? You are doing it wrong!
  • 79. Selenium Sandwich Sandwich the browser between tasty layers of Perl: use Plack; use Selenium;
  • 80. Metadata-driven selenium testing Four structs define an iteration: [ [ DOM contents ], [ Expected values ], [ return struct ], [ result DOM ] ]
  • 81. Failing successfully Return the HTTP failure code: [ [ DOM contents ], [ Expected values ], [ 404, “Oops...”, ], [ result DOM ] ]
  • 82. Summary Avoid “red flags”. Use data to drive tests. Metadata to generate the data. Abstract your tests.
  • 83. Bedside reading Object::Exercise Selenium Sandwich Getting Testy with Perl https://www.slideshare.net/lembark