SlideShare a Scribd company logo
1 of 68
Download to read offline
Getting There from Here:
Unit testing a few generations of code.
Steven Lembark
Workhorse Computing
lembark@wrkhors.com
perl 5.8
Fun isn’t it? A generation of nothing.
No improvements in Perl.
No advances in CPAN.
No reason to upgrade.
20 years of nada...
Ask all the programmers stuck with 5.8.
perl 5.8
Q: Why are we stuck with 5.8?
A: /usr/bin/perl is 5.8
Q: Why are we stuck with /usr/bin/perl?
A: ???
perl 5.8
Q: Why are we stuck with 5.8?
A: /usr/bin/perl is 5.8
Q: Why are we stuck with /usr/bin/perl?
A: Because “it worked”.
perl 5.8
Q: Why are we stuck with 5.8?
A: /usr/bin/perl is 5.8
Q: Why are we stuck with /usr/bin/perl?
A: Because something else “might not” work.
perl 5.8
Q: Why are we stuck with 5.8?
A: /usr/bin/perl is 5.8
Q: Why are we stuck with /usr/bin/perl?
A: Because we can’t show that 5.X works.
(for some definition of Christmas > 5.8)
perl 5.X
Q: Why can’t we show that 5.X works?
A: Because Christmas came after 2002.
perl 5.X
Q: Why can’t we show that 5.X works?
A: Because we stopped testing our code.
perl 5.X
Q: Why can’t we show that 5.X works?
A: Because they stopped testing our code.
perl 5.X
Q: Why can’t we show that 5.X works?
A: Because we have worked around it for way too long.
perl 5.X
Q: Why can’t we show that 5.X works?
A: Because we have worked around it for way too long.
perlbrew, all of the other approaches to dodging
/usr/bin/perl.
OK how do we fix it?
Prove that “it works”.
With testing.
In one client’s case: Lots and lots of testing.
OK how do we fix it?
Prove that “it works”.
With testing.
In one client’s case: Lots and lots of testing.
75_000 modules worth of testing.
OK how do we fix it?
Prove that “it works”.
With testing.
In one client’s case: Lots and lots of testing.
75_000 modules worth of testing.
Q: But how did you write 75_000 unit tests?
OK how do we fix it?
Prove that “it works”.
With testing.
In one client’s case: Lots and lots of testing.
75_000 modules worth of automated testing.
A: Lazyness.
Syntax checks are the first pass.
Unit tests get a bad rap.
“They don’t really test anything.”
Syntax checks are the first pass.
Unit tests get a bad rap.
“They don’t really test anything.”
Except whether 75_000 modules compile.
Code that was written on 5.8.
That now to run on 5.20+.
How do we test that much code?
Metadata driven testing:
Encode data into a test.
The standard test is data-driven.
Tests each validate one small part of a module.
How do we test that much code?
Q: How do you write that many tests?
A: Don’t.
How do we test that much code?
Q: How do you write that many tests?
A: Don’t.
Symlinks are your friends.
Simple basic test: require_ok
Run “require_ok $module” for every *.pm.
Simple, basic, obvious test for syntax errors.
… missing modules.
… botched system paths.
… all sorts of things.
Simple basic test: require_ok
Run “require_ok $module” for every *.pm.
Simple, basic, obvious test for syntax errors.
Nice thing: $module can be a path.
Even an absolute path.
Passing a path
“require_ok $path”
One argument.
Q: How do we pass it?
A: In the basename of a test.
Basic unit test
use v5.30;
use Test::More;
use File::Basename;
my $base0 = basename $0, '.t';
my $s = substr $base0, 0, 1;
my $path = join ‘/’, split m{[$s]}, $base0;
require_ok $path;
done_testing
__END__
Basic unit test
Install
them
using
shell.
#!/bin/bash
dir=$(cd $(dirname $0)/../..; pwd -L);
cd “$dir/t/01-units”;
find $dir/lib -name ‘*pm’ |
while read i
do
base=”$(echo $i | tr ‘/’ ‘~’).t”;
ln -fs ../bin/01-unit_t ./$base;
done
Basic unit test
Install
them
using
shell.
From
./t/bin
#!/bin/bash
dir=$(cd $(dirname $0)/../..; pwd -L);
cd “$dir/t/01-units”;
find $dir/lib -name ‘*pm’ |
while read i
do
base=”$(echo $i | tr ‘/’ ‘~’).t”;
ln -fs ../bin/01-unit_t ./$base;
done
Basic unit test
Install
them
using
shell.
Path to
basename.
#!/bin/bash
dir=$(cd $(dirname $0)/../..; pwd -L);
cd “$dir/t/01-units”;
find $dir/lib -name ‘*pm’ |
while read i
do
base=”$(echo $i | tr ‘/’ ‘~’).t”;
ln -fs ../bin/01-unit_t ./$base;
done
Basic unit test
Now you
know if it
compiles. prove t/01-units;
Basic unit test
Now you
know if it
compiles.
A bit
faster.
prove --jobs=8 t/01-units;
Basic unit test
Now you
know if it
compiles.
At 3am
without
watching.
args=(--jobs=8 --state=save );
prove ${args[*]} t/01-units;
Basic unit test
Now you
know if it
compiles.
At 8am
knowing
what
failed.
args=(--jobs=8 --state=save,failed );
prove ${args[*]} t/01-units;
Basic unit test
Now you
know if it
compiles.
Missing
module
anyone?
args=(--jobs=8 --state=save,failed );
prove ${args[*]} t/01-units
Can't locate Foo/Bar.pm in @INC (you
may need to install the Foo::Bar
module) (@INC contains:
/opt/perl/5.30/lib/site_perl/5.30.1/x8
6_64-linux
Basic unit test
Now you
know if it
compiles.
Fine:
Install
them.
args=(--jobs=8 --state=save,failed );
prove ${args[*]} t/01-units |
grep ‘you may need to install the’ |
cut -d’(‘ -f2 |
cut -d’ ‘ -f7 |
sort -d |
uniq |
cpanm ;
Basic unit test
Now you
know if it
compiles.
Local
mirror
provides
pre-
verified
modules.
args=(--jobs=8 --state=save,failed );
prove ${args[*]} t/01-units |
grep ‘you may need to install the’ |
cut -d’(‘ -f2 |
cut -d’ ‘ -f7 |
sort -d |
uniq |
cpanm -M$local ;
Basic unit test
Now you
know if it
compiles.
Local
library
simplifies
auto-
install.
args=(--jobs=8 --state=save,failed );
prove ${args[*]} t/01-units |
grep ‘you may need to install the’ |
cut -d’(‘ -f2 |
cut -d’ ‘ -f7 |
sort -d |
uniq |
cpanm 
-M$local -l$repo --self-contained ;
Basic unit test
Start with
a virgin
/opt/perl.
Keep
testing
until it’s
all use-
able.
args=(--jobs=8 --state=save,failed );
prove ${args[*]} t/01-units |
grep ‘you may need to install the’ |
cut -d’(‘ -f2 |
cut -d’ ‘ -f7 |
sort -d |
uniq |
cpanm 
-M$local -l$repo --self-contained ;
Version control what you install
git submodule add blah://.../site_perl;
perl Makefile.PL INSTALL_BASE=$PWD/site_perl;
cpanm --local-library=$PWD/site_perl;
If anyone asks, you know what non-core modules have
been installed.
If anything breaks, check out the last commit.
What else can we do with a path?
Ever fat-finger
a package?
package AcmeWigdit::Config;
use v5.30;
What else can we do with a path?
Ever fat-finger
a package?
Paths define
packages.
require_ok $path or skip ... ;
my ($sub)
= $path
=~ m{^.+?/lib/(.+?) [.]pm}x;
my $pkg = $sub =~ s{/}{::}g;
isa_ok $pkg, ‘UNIVERSAL’
or skip “$pkg not ‘UNIVERSAL’”;
$pkg->can( ‘VERSION’ )
or skip “$path missing $pkg”, 1;
What else can we do with a path?
Ever fat-finger
a package?
Paths define
packages.
All defined
packages are
UNIVERSAL.
require_ok $path or skip ... ;
my ($sub)
= $path
=~ m{^.+?/lib/(.+?) [.]pm}x;
my $pkg = $sub =~ s{/}{::}g;
isa_ok $pkg, ‘UNIVERSAL’
or skip “$pkg not ‘UNIVERSAL’”;
$pkg->can( ‘VERSION’ )
or skip “$path missing $pkg”, 1;
What else can we do with a path?
Ever fat-finger
a package?
Paths define
packages.
VERSION is
UNIVERSAL.
require_ok $path or skip ... ;
my ($sub)
= $path
=~ m{^.+?/lib/(.+?) [.]pm}x;
my $pkg = $sub =~ s{/}{::}g;
is_ok $pkg, ‘UNIVERSAL’
or skip “$pkg not ‘UNIVERSAL’”;
$pkg->can( ‘VERSION’ )
or skip “$path missing $pkg”, 1;
Minor issue with paths
Packages are related to paths.
We know that now.
In 2000 not everyone got that.
Minor issue with paths
What about:
package <basename>;
use lib <every directory everywhere>;
It works, but there are better ways...
Minor issue with paths
One pattern: Overlapping product of evolution.
./lib/AcmeWig/
./lib/AcmeWig/Config.pm AcmeWig::Config
Minor issue with paths
One pattern: Overlapping product of evolution.
./lib/AcmeWig/
./lib/AcmeWig/Config.pm AcmeWig::Config
Minor issue with paths
One pattern: Overlapping product of evolution.
./lib/AcmeWig/
./lib/AcmeWig/Config.pm AcmeWig::Config
./lib/AcmeWig/Acme/Config.pm Acme::Config
Minor issue with paths
One pattern: Overlapping product of evolution.
./lib/AcmeWig/
./lib/AcmeWig/Config.pm AcmeWig::Config
./lib/AcmeWig/Acme/Config.pm Acme::Config
What’s the expected package?
Solving nested paths
Say we figure out the paths:
qw
(
./lib/AcmeWig
./lib/AcmeWig/Acme
./lib/AcmeWig/Acme/Plastic/External
./lib/AcmeWig/Acme/Plastic/Internal
./lib/AcmeWig/Acme/Plastic/Wrappers
./lib/AcmeWig/Plastic
./lib/AcmeWig/AcmeWig/External/Plastic
)
Solving nested paths
We can obviously iterate them...
qw
(
./lib/AcmeWig
./lib/AcmeWig/Acme
./lib/AcmeWig/Acme/Plastic/External
./lib/AcmeWig/Acme/Plastic/Internal
./lib/AcmeWig/Acme/Plastic/Wrappers
./lib/AcmeWig/Plastic
./lib/AcmeWig/AcmeWig/External/Plastic
)
Solving nested paths
Q: But how do we avoid duplicate tests?
qw
(
./lib/AcmeWig
./lib/AcmeWig/Acme
./lib/AcmeWig/Acme/Plastic/External
./lib/AcmeWig/Acme/Plastic/Internal
./lib/AcmeWig/Acme/Plastic/Wrappers
./lib/AcmeWig/Plastic
./lib/AcmeWig/AcmeWig/External/Plastic
)
Solving nested paths
A: Sort them by length.
qw
(
./lib/AcmeWig/AcmeWig/External/Plastic
./lib/AcmeWig/Acme/Plastic/External
./lib/AcmeWig/Acme/Plastic/Internal
./lib/AcmeWig/Acme/Plastic/Wrappers
./lib/AcmeWig/Plastic
./lib/AcmeWig/Acme
./lib/AcmeWig
)
Solving nested paths
A: Sort them by length & exclude known paths.
qw
(
./lib/AcmeWig/AcmeWig/External/Plastic
./lib/AcmeWig/Acme/Plastic/External
./lib/AcmeWig/Acme/Plastic/Internal
./lib/AcmeWig/Acme/Plastic/Wrappers
./lib/AcmeWig/Plastic
./lib/AcmeWig/Acme
./lib/AcmeWig
)
Solving nested paths
my %prune = ();
my $wanted = sub
{
-d && exists $prune{ $File::Find::dir }
? $File::Find::prune = 1
: $File::Find::Path->$install_test_symlink
};
for my $dir ( @dirs_sorted_by_length )
{
find $wanted, $dir;
$prune{ $dir } = ();
}
Solving nested paths
my %prune = ();
my $wanted = sub
{
-d && exists $prune{ $File::Find::dir }
? $File::Find::prune = 1
: $File::Find::Path->$install_test_symlink
};
for my $dir ( @dirs_sorted_by_length )
{
find $wanted, $dir;
$prune{ $dir } = (); # don’t revisit
}
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Fix: Double the separator.
~path~to~repo~lib~AcmeWig~Acme~Config.pm.t
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Fix: Double the separator.
~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Fix: ‘//’ works fine with require_ok.
~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t
/path/to/repo/lib/AcmeWig//Acme/Config.pm.t
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Fix: Gives sub-path for module.
~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t
Acme~Config.pm.t
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Fix: basename with s{~}{::}.
~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t
Acme::Config
Testing nested paths
Catch: The test needs to know its ‘root’ directory.
Has to subtract that to get the expected package.
Save the search dir’s length and substr in a ‘~’:
my $l = length $dir;
...
substr $symlink, $l, 0, ‘~’;
Skipping test groups
We started with 75_000 files.
Found some dirs we didn’t want to test.
Fix:
my @no_test = qw( … );
my %prune = ();
@prune{ @no_test } = ();
Net result
We were able to test 45_000+ files each night.
Found missing modules.
Found outdated syntax.
Managed to get it all working.
Largey with “require_ok”.
Knowledge is power
Unit tests are useful.
Provide automated, reproducable results.
No excuse for “It may not work in v5.30.”
We can know.
And fix whatever “it” is.
For some definition of Perl5
Perl7 is coming.
Adopting it requires showing that “it works.”
Which means finding where it doesn’t.
Unit testing all of CPAN.
Unit testing all of everything.
For some definition of Perl5
Perl7 is coming.
Adopting it requires showing that “it works.”
Which means finding where it doesn’t.
Unit testing all of CPAN.
Unit testing all of everything.
We just have to be lazy about it.
Units of your very own!
In case you don’t like pasting from PDF:
https://gitlab.com/lembark/perl5-unit-tests
If anyone wants to work on this we can release it as
App::Testify or Test2::Unitz …
Be nice to have a migration suite for Perl7.
Units of your very own!
A wider range of unit tests is shown at:
https://www.slideshare.net/lembark/path-toknowlege
With a little bit of work we could get them all on CPAN.

More Related Content

What's hot

The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.Workhorse Computing
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationWorkhorse Computing
 
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.Workhorse Computing
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Puppet
 
Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2nottings
 
Puppet: What _not_ to do
Puppet: What _not_ to doPuppet: What _not_ to do
Puppet: What _not_ to doPuppet
 
Test-Driven Puppet Development - PuppetConf 2014
Test-Driven Puppet Development - PuppetConf 2014Test-Driven Puppet Development - PuppetConf 2014
Test-Driven Puppet Development - PuppetConf 2014Puppet
 
Puppet loves RSpec, why you should, too
Puppet loves RSpec, why you should, tooPuppet loves RSpec, why you should, too
Puppet loves RSpec, why you should, tooDennis Rowe
 
What you need to remember when you upload to CPAN
What you need to remember when you upload to CPANWhat you need to remember when you upload to CPAN
What you need to remember when you upload to CPANcharsbar
 
Better detection of what modules are used by some Perl 5 code
Better detection of what modules are used by some Perl 5 codeBetter detection of what modules are used by some Perl 5 code
Better detection of what modules are used by some Perl 5 codecharsbar
 
Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Martin Alfke
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidenceJohn Congdon
 
SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)Robert Swisher
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksWorkhorse Computing
 
Working with databases in Perl
Working with databases in PerlWorking with databases in Perl
Working with databases in PerlLaurent Dami
 
Puppet modules for Fun and Profit
Puppet modules for Fun and ProfitPuppet modules for Fun and Profit
Puppet modules for Fun and ProfitAlessandro Franceschi
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Puppet
 
PL/Perl - New Features in PostgreSQL 9.0
PL/Perl - New Features in PostgreSQL 9.0PL/Perl - New Features in PostgreSQL 9.0
PL/Perl - New Features in PostgreSQL 9.0Tim Bunce
 

What's hot (20)

The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
 
Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
 
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.
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...
 
Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2Puppet camp chicago-automated_testing2
Puppet camp chicago-automated_testing2
 
Puppet: What _not_ to do
Puppet: What _not_ to doPuppet: What _not_ to do
Puppet: What _not_ to do
 
Test-Driven Puppet Development - PuppetConf 2014
Test-Driven Puppet Development - PuppetConf 2014Test-Driven Puppet Development - PuppetConf 2014
Test-Driven Puppet Development - PuppetConf 2014
 
Troubleshooting Puppet
Troubleshooting PuppetTroubleshooting Puppet
Troubleshooting Puppet
 
Puppet loves RSpec, why you should, too
Puppet loves RSpec, why you should, tooPuppet loves RSpec, why you should, too
Puppet loves RSpec, why you should, too
 
What you need to remember when you upload to CPAN
What you need to remember when you upload to CPANWhat you need to remember when you upload to CPAN
What you need to remember when you upload to CPAN
 
Better detection of what modules are used by some Perl 5 code
Better detection of what modules are used by some Perl 5 codeBetter detection of what modules are used by some Perl 5 code
Better detection of what modules are used by some Perl 5 code
 
Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?Can you upgrade to Puppet 4.x?
Can you upgrade to Puppet 4.x?
 
Release with confidence
Release with confidenceRelease with confidence
Release with confidence
 
SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)SDPHP - Percona Toolkit (It's Basically Magic)
SDPHP - Percona Toolkit (It's Basically Magic)
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and Benchmarks
 
Working with databases in Perl
Working with databases in PerlWorking with databases in Perl
Working with databases in Perl
 
Puppet modules for Fun and Profit
Puppet modules for Fun and ProfitPuppet modules for Fun and Profit
Puppet modules for Fun and Profit
 
Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014Test Driven Development with Puppet - PuppetConf 2014
Test Driven Development with Puppet - PuppetConf 2014
 
PL/Perl - New Features in PostgreSQL 9.0
PL/Perl - New Features in PostgreSQL 9.0PL/Perl - New Features in PostgreSQL 9.0
PL/Perl - New Features in PostgreSQL 9.0
 

Similar to Unit Testing Lots of Perl

Continuous Integration Testing in Django
Continuous Integration Testing in DjangoContinuous Integration Testing in Django
Continuous Integration Testing in DjangoKevin Harvey
 
Ansible roles done right
Ansible roles done rightAnsible roles done right
Ansible roles done rightDan Vaida
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?NETWAYS
 
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...Puppet
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl TechniquesDave Cross
 
How I hack on puppet modules
How I hack on puppet modulesHow I hack on puppet modules
How I hack on puppet modulesKris Buytaert
 
Drupal Camp Brighton 2015: Ansible Drupal Medicine show
Drupal Camp Brighton 2015: Ansible Drupal Medicine showDrupal Camp Brighton 2015: Ansible Drupal Medicine show
Drupal Camp Brighton 2015: Ansible Drupal Medicine showGeorge Boobyer
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet CampPuppet
 
Angular JS in 2017
Angular JS in 2017Angular JS in 2017
Angular JS in 2017Ayush Sharma
 
Autotesting rails app
Autotesting rails appAutotesting rails app
Autotesting rails appAnton Naumenko
 
Testing Ansible
Testing AnsibleTesting Ansible
Testing AnsibleAnth Courtney
 
Ansible with oci
Ansible with ociAnsible with oci
Ansible with ociDonghuKIM2
 
Automate Yo' Self
Automate Yo' SelfAutomate Yo' Self
Automate Yo' SelfJohn Anderson
 
Automate Yo'self -- SeaGL
Automate Yo'self -- SeaGL Automate Yo'self -- SeaGL
Automate Yo'self -- SeaGL John Anderson
 

Similar to Unit Testing Lots of Perl (20)

Metadata-driven Testing
Metadata-driven TestingMetadata-driven Testing
Metadata-driven Testing
 
Continuous Integration Testing in Django
Continuous Integration Testing in DjangoContinuous Integration Testing in Django
Continuous Integration Testing in Django
 
Ansible roles done right
Ansible roles done rightAnsible roles done right
Ansible roles done right
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Ansible testing
Ansible   testingAnsible   testing
Ansible testing
 
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
Puppet Camp Duesseldorf 2014: Martin Alfke - Can you upgrade to puppet 4.x?
 
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
Can you upgrade to Puppet 4.x? (Beginner) Can you upgrade to Puppet 4.x? (Beg...
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
How I hack on puppet modules
How I hack on puppet modulesHow I hack on puppet modules
How I hack on puppet modules
 
Drupal Camp Brighton 2015: Ansible Drupal Medicine show
Drupal Camp Brighton 2015: Ansible Drupal Medicine showDrupal Camp Brighton 2015: Ansible Drupal Medicine show
Drupal Camp Brighton 2015: Ansible Drupal Medicine show
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
 
Angular JS in 2017
Angular JS in 2017Angular JS in 2017
Angular JS in 2017
 
Autotesting rails app
Autotesting rails appAutotesting rails app
Autotesting rails app
 
Testing Ansible
Testing AnsibleTesting Ansible
Testing Ansible
 
Docker perl build
Docker perl buildDocker perl build
Docker perl build
 
IntroTestMore
IntroTestMoreIntroTestMore
IntroTestMore
 
IntroTestMore
IntroTestMoreIntroTestMore
IntroTestMore
 
Ansible with oci
Ansible with ociAnsible with oci
Ansible with oci
 
Automate Yo' Self
Automate Yo' SelfAutomate Yo' Self
Automate Yo' Self
 
Automate Yo'self -- SeaGL
Automate Yo'self -- SeaGL Automate Yo'self -- SeaGL
Automate Yo'self -- SeaGL
 

More from Workhorse Computing

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 ModulesWorkhorse Computing
 
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 UpWorkhorse Computing
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlGenerating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in PosgresqlWorkhorse Computing
 
Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Workhorse Computing
 
The W-curve and its application.
The W-curve and its application.The W-curve and its application.
The W-curve and its application.Workhorse Computing
 
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
 
Putting some "logic" in LVM.
Putting some "logic" in LVM.Putting some "logic" in LVM.
Putting some "logic" in LVM.Workhorse Computing
 
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.Workhorse Computing
 
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 Workhorse Computing
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Workhorse Computing
 

More from Workhorse Computing (18)

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
 
Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!
 
Findbin libs
Findbin libsFindbin libs
Findbin libs
 
The W-curve and its application.
The W-curve and its application.The W-curve and its application.
The W-curve and its application.
 
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.
 
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
 
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
 
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
 
Designing net-aws-glacier
Designing net-aws-glacierDesigning net-aws-glacier
Designing net-aws-glacier
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6
 

Recently uploaded

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
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
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
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
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
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
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
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
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
 

Recently uploaded (20)

Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort ServiceHot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
 
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
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
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
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
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
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
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
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
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
 

Unit Testing Lots of Perl

  • 1. Getting There from Here: Unit testing a few generations of code. Steven Lembark Workhorse Computing lembark@wrkhors.com
  • 2. perl 5.8 Fun isn’t it? A generation of nothing. No improvements in Perl. No advances in CPAN. No reason to upgrade. 20 years of nada... Ask all the programmers stuck with 5.8.
  • 3. perl 5.8 Q: Why are we stuck with 5.8? A: /usr/bin/perl is 5.8 Q: Why are we stuck with /usr/bin/perl? A: ???
  • 4. perl 5.8 Q: Why are we stuck with 5.8? A: /usr/bin/perl is 5.8 Q: Why are we stuck with /usr/bin/perl? A: Because “it worked”.
  • 5. perl 5.8 Q: Why are we stuck with 5.8? A: /usr/bin/perl is 5.8 Q: Why are we stuck with /usr/bin/perl? A: Because something else “might not” work.
  • 6. perl 5.8 Q: Why are we stuck with 5.8? A: /usr/bin/perl is 5.8 Q: Why are we stuck with /usr/bin/perl? A: Because we can’t show that 5.X works. (for some definition of Christmas > 5.8)
  • 7. perl 5.X Q: Why can’t we show that 5.X works? A: Because Christmas came after 2002.
  • 8. perl 5.X Q: Why can’t we show that 5.X works? A: Because we stopped testing our code.
  • 9. perl 5.X Q: Why can’t we show that 5.X works? A: Because they stopped testing our code.
  • 10. perl 5.X Q: Why can’t we show that 5.X works? A: Because we have worked around it for way too long.
  • 11. perl 5.X Q: Why can’t we show that 5.X works? A: Because we have worked around it for way too long. perlbrew, all of the other approaches to dodging /usr/bin/perl.
  • 12. OK how do we fix it? Prove that “it works”. With testing. In one client’s case: Lots and lots of testing.
  • 13. OK how do we fix it? Prove that “it works”. With testing. In one client’s case: Lots and lots of testing. 75_000 modules worth of testing.
  • 14. OK how do we fix it? Prove that “it works”. With testing. In one client’s case: Lots and lots of testing. 75_000 modules worth of testing. Q: But how did you write 75_000 unit tests?
  • 15. OK how do we fix it? Prove that “it works”. With testing. In one client’s case: Lots and lots of testing. 75_000 modules worth of automated testing. A: Lazyness.
  • 16. Syntax checks are the first pass. Unit tests get a bad rap. “They don’t really test anything.”
  • 17. Syntax checks are the first pass. Unit tests get a bad rap. “They don’t really test anything.” Except whether 75_000 modules compile. Code that was written on 5.8. That now to run on 5.20+.
  • 18. How do we test that much code? Metadata driven testing: Encode data into a test. The standard test is data-driven. Tests each validate one small part of a module.
  • 19. How do we test that much code? Q: How do you write that many tests? A: Don’t.
  • 20. How do we test that much code? Q: How do you write that many tests? A: Don’t. Symlinks are your friends.
  • 21. Simple basic test: require_ok Run “require_ok $module” for every *.pm. Simple, basic, obvious test for syntax errors. … missing modules. … botched system paths. … all sorts of things.
  • 22. Simple basic test: require_ok Run “require_ok $module” for every *.pm. Simple, basic, obvious test for syntax errors. Nice thing: $module can be a path. Even an absolute path.
  • 23. Passing a path “require_ok $path” One argument. Q: How do we pass it? A: In the basename of a test.
  • 24. Basic unit test use v5.30; use Test::More; use File::Basename; my $base0 = basename $0, '.t'; my $s = substr $base0, 0, 1; my $path = join ‘/’, split m{[$s]}, $base0; require_ok $path; done_testing __END__
  • 25. Basic unit test Install them using shell. #!/bin/bash dir=$(cd $(dirname $0)/../..; pwd -L); cd “$dir/t/01-units”; find $dir/lib -name ‘*pm’ | while read i do base=”$(echo $i | tr ‘/’ ‘~’).t”; ln -fs ../bin/01-unit_t ./$base; done
  • 26. Basic unit test Install them using shell. From ./t/bin #!/bin/bash dir=$(cd $(dirname $0)/../..; pwd -L); cd “$dir/t/01-units”; find $dir/lib -name ‘*pm’ | while read i do base=”$(echo $i | tr ‘/’ ‘~’).t”; ln -fs ../bin/01-unit_t ./$base; done
  • 27. Basic unit test Install them using shell. Path to basename. #!/bin/bash dir=$(cd $(dirname $0)/../..; pwd -L); cd “$dir/t/01-units”; find $dir/lib -name ‘*pm’ | while read i do base=”$(echo $i | tr ‘/’ ‘~’).t”; ln -fs ../bin/01-unit_t ./$base; done
  • 28. Basic unit test Now you know if it compiles. prove t/01-units;
  • 29. Basic unit test Now you know if it compiles. A bit faster. prove --jobs=8 t/01-units;
  • 30. Basic unit test Now you know if it compiles. At 3am without watching. args=(--jobs=8 --state=save ); prove ${args[*]} t/01-units;
  • 31. Basic unit test Now you know if it compiles. At 8am knowing what failed. args=(--jobs=8 --state=save,failed ); prove ${args[*]} t/01-units;
  • 32. Basic unit test Now you know if it compiles. Missing module anyone? args=(--jobs=8 --state=save,failed ); prove ${args[*]} t/01-units Can't locate Foo/Bar.pm in @INC (you may need to install the Foo::Bar module) (@INC contains: /opt/perl/5.30/lib/site_perl/5.30.1/x8 6_64-linux
  • 33. Basic unit test Now you know if it compiles. Fine: Install them. args=(--jobs=8 --state=save,failed ); prove ${args[*]} t/01-units | grep ‘you may need to install the’ | cut -d’(‘ -f2 | cut -d’ ‘ -f7 | sort -d | uniq | cpanm ;
  • 34. Basic unit test Now you know if it compiles. Local mirror provides pre- verified modules. args=(--jobs=8 --state=save,failed ); prove ${args[*]} t/01-units | grep ‘you may need to install the’ | cut -d’(‘ -f2 | cut -d’ ‘ -f7 | sort -d | uniq | cpanm -M$local ;
  • 35. Basic unit test Now you know if it compiles. Local library simplifies auto- install. args=(--jobs=8 --state=save,failed ); prove ${args[*]} t/01-units | grep ‘you may need to install the’ | cut -d’(‘ -f2 | cut -d’ ‘ -f7 | sort -d | uniq | cpanm -M$local -l$repo --self-contained ;
  • 36. Basic unit test Start with a virgin /opt/perl. Keep testing until it’s all use- able. args=(--jobs=8 --state=save,failed ); prove ${args[*]} t/01-units | grep ‘you may need to install the’ | cut -d’(‘ -f2 | cut -d’ ‘ -f7 | sort -d | uniq | cpanm -M$local -l$repo --self-contained ;
  • 37. Version control what you install git submodule add blah://.../site_perl; perl Makefile.PL INSTALL_BASE=$PWD/site_perl; cpanm --local-library=$PWD/site_perl; If anyone asks, you know what non-core modules have been installed. If anything breaks, check out the last commit.
  • 38. What else can we do with a path? Ever fat-finger a package? package AcmeWigdit::Config; use v5.30;
  • 39. What else can we do with a path? Ever fat-finger a package? Paths define packages. require_ok $path or skip ... ; my ($sub) = $path =~ m{^.+?/lib/(.+?) [.]pm}x; my $pkg = $sub =~ s{/}{::}g; isa_ok $pkg, ‘UNIVERSAL’ or skip “$pkg not ‘UNIVERSAL’”; $pkg->can( ‘VERSION’ ) or skip “$path missing $pkg”, 1;
  • 40. What else can we do with a path? Ever fat-finger a package? Paths define packages. All defined packages are UNIVERSAL. require_ok $path or skip ... ; my ($sub) = $path =~ m{^.+?/lib/(.+?) [.]pm}x; my $pkg = $sub =~ s{/}{::}g; isa_ok $pkg, ‘UNIVERSAL’ or skip “$pkg not ‘UNIVERSAL’”; $pkg->can( ‘VERSION’ ) or skip “$path missing $pkg”, 1;
  • 41. What else can we do with a path? Ever fat-finger a package? Paths define packages. VERSION is UNIVERSAL. require_ok $path or skip ... ; my ($sub) = $path =~ m{^.+?/lib/(.+?) [.]pm}x; my $pkg = $sub =~ s{/}{::}g; is_ok $pkg, ‘UNIVERSAL’ or skip “$pkg not ‘UNIVERSAL’”; $pkg->can( ‘VERSION’ ) or skip “$path missing $pkg”, 1;
  • 42. Minor issue with paths Packages are related to paths. We know that now. In 2000 not everyone got that.
  • 43. Minor issue with paths What about: package <basename>; use lib <every directory everywhere>; It works, but there are better ways...
  • 44. Minor issue with paths One pattern: Overlapping product of evolution. ./lib/AcmeWig/ ./lib/AcmeWig/Config.pm AcmeWig::Config
  • 45. Minor issue with paths One pattern: Overlapping product of evolution. ./lib/AcmeWig/ ./lib/AcmeWig/Config.pm AcmeWig::Config
  • 46. Minor issue with paths One pattern: Overlapping product of evolution. ./lib/AcmeWig/ ./lib/AcmeWig/Config.pm AcmeWig::Config ./lib/AcmeWig/Acme/Config.pm Acme::Config
  • 47. Minor issue with paths One pattern: Overlapping product of evolution. ./lib/AcmeWig/ ./lib/AcmeWig/Config.pm AcmeWig::Config ./lib/AcmeWig/Acme/Config.pm Acme::Config What’s the expected package?
  • 48. Solving nested paths Say we figure out the paths: qw ( ./lib/AcmeWig ./lib/AcmeWig/Acme ./lib/AcmeWig/Acme/Plastic/External ./lib/AcmeWig/Acme/Plastic/Internal ./lib/AcmeWig/Acme/Plastic/Wrappers ./lib/AcmeWig/Plastic ./lib/AcmeWig/AcmeWig/External/Plastic )
  • 49. Solving nested paths We can obviously iterate them... qw ( ./lib/AcmeWig ./lib/AcmeWig/Acme ./lib/AcmeWig/Acme/Plastic/External ./lib/AcmeWig/Acme/Plastic/Internal ./lib/AcmeWig/Acme/Plastic/Wrappers ./lib/AcmeWig/Plastic ./lib/AcmeWig/AcmeWig/External/Plastic )
  • 50. Solving nested paths Q: But how do we avoid duplicate tests? qw ( ./lib/AcmeWig ./lib/AcmeWig/Acme ./lib/AcmeWig/Acme/Plastic/External ./lib/AcmeWig/Acme/Plastic/Internal ./lib/AcmeWig/Acme/Plastic/Wrappers ./lib/AcmeWig/Plastic ./lib/AcmeWig/AcmeWig/External/Plastic )
  • 51. Solving nested paths A: Sort them by length. qw ( ./lib/AcmeWig/AcmeWig/External/Plastic ./lib/AcmeWig/Acme/Plastic/External ./lib/AcmeWig/Acme/Plastic/Internal ./lib/AcmeWig/Acme/Plastic/Wrappers ./lib/AcmeWig/Plastic ./lib/AcmeWig/Acme ./lib/AcmeWig )
  • 52. Solving nested paths A: Sort them by length & exclude known paths. qw ( ./lib/AcmeWig/AcmeWig/External/Plastic ./lib/AcmeWig/Acme/Plastic/External ./lib/AcmeWig/Acme/Plastic/Internal ./lib/AcmeWig/Acme/Plastic/Wrappers ./lib/AcmeWig/Plastic ./lib/AcmeWig/Acme ./lib/AcmeWig )
  • 53. Solving nested paths my %prune = (); my $wanted = sub { -d && exists $prune{ $File::Find::dir } ? $File::Find::prune = 1 : $File::Find::Path->$install_test_symlink }; for my $dir ( @dirs_sorted_by_length ) { find $wanted, $dir; $prune{ $dir } = (); }
  • 54. Solving nested paths my %prune = (); my $wanted = sub { -d && exists $prune{ $File::Find::dir } ? $File::Find::prune = 1 : $File::Find::Path->$install_test_symlink }; for my $dir ( @dirs_sorted_by_length ) { find $wanted, $dir; $prune{ $dir } = (); # don’t revisit }
  • 55. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package.
  • 56. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package. Fix: Double the separator. ~path~to~repo~lib~AcmeWig~Acme~Config.pm.t
  • 57. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package. Fix: Double the separator. ~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t
  • 58. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package. Fix: ‘//’ works fine with require_ok. ~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t /path/to/repo/lib/AcmeWig//Acme/Config.pm.t
  • 59. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package. Fix: Gives sub-path for module. ~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t Acme~Config.pm.t
  • 60. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package. Fix: basename with s{~}{::}. ~path~to~repo~lib~AcmeWig~~Acme~Config.pm.t Acme::Config
  • 61. Testing nested paths Catch: The test needs to know its ‘root’ directory. Has to subtract that to get the expected package. Save the search dir’s length and substr in a ‘~’: my $l = length $dir; ... substr $symlink, $l, 0, ‘~’;
  • 62. Skipping test groups We started with 75_000 files. Found some dirs we didn’t want to test. Fix: my @no_test = qw( … ); my %prune = (); @prune{ @no_test } = ();
  • 63. Net result We were able to test 45_000+ files each night. Found missing modules. Found outdated syntax. Managed to get it all working. Largey with “require_ok”.
  • 64. Knowledge is power Unit tests are useful. Provide automated, reproducable results. No excuse for “It may not work in v5.30.” We can know. And fix whatever “it” is.
  • 65. For some definition of Perl5 Perl7 is coming. Adopting it requires showing that “it works.” Which means finding where it doesn’t. Unit testing all of CPAN. Unit testing all of everything.
  • 66. For some definition of Perl5 Perl7 is coming. Adopting it requires showing that “it works.” Which means finding where it doesn’t. Unit testing all of CPAN. Unit testing all of everything. We just have to be lazy about it.
  • 67. Units of your very own! In case you don’t like pasting from PDF: https://gitlab.com/lembark/perl5-unit-tests If anyone wants to work on this we can release it as App::Testify or Test2::Unitz … Be nice to have a migration suite for Perl7.
  • 68. Units of your very own! A wider range of unit tests is shown at: https://www.slideshare.net/lembark/path-toknowlege With a little bit of work we could get them all on CPAN.