A Whirlwind Tour of Test::Class
-
Upload
curtis-poe -
Category
Technology
-
view
12.484 -
download
2
Transcript of A Whirlwind Tour of Test::Class
OO tests for OO code Nice performance boost Easy-to-organize test suites
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Plenty!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
use strict;!use warnings;!use Test::Exception 0.88;!use Test::Differences 0.500;!use Test::Deep 0.106;!use Test::Warn 0.11;!use Test::More 0.88;!
use parent 'My::Test::Class’;!sub some_test : Tests { ... }!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
use Test::Class::Most! parent => 'My::Test::Class’;!
sub some_test : Tests { ... }!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
lib/!| Person/!| `-- Employee.pm!`-- Person.pm!
t/!| lib/!| | My/!| | | Test/!| | | `-- Class.pm!| | TestsFor/!| | | Person/!| | | `-- Employee.pm!| | `-- Person.pm!`-- test_class_tests.t!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package My::Test::Class;!use Test::Class::Most ! attributes => ['class'];!
INIT { Test::Class->runtests }!
sub startup : Tests(startup) {…}!sub setup : Tests(setup) {}!sub teardown : Tests(teardown) {}!sub shutdown : Tests(shutdown) {}!
1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package My::Test::Class;!use Test::Class::Most ! attributes => ['class'];!
INIT { Test::Class->runtests }!
sub startup : Tests(startup) {…}!sub setup : Tests(setup) {}!sub teardown : Tests(teardown) {}!sub shutdown : Tests(shutdown) {}!
1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package My::Test::Class;!use Test::Class::Most ! attributes => ['class'];!
INIT { Test::Class->runtests }!
sub startup : Tests(startup) {…}!sub setup : Tests(setup) {}!sub teardown : Tests(teardown) {}!sub shutdown : Tests(shutdown) {}!
1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package My::Test::Class;!use Test::Class::Most ! attributes => ['class'];!
INIT { Test::Class->runtests }!
sub startup : Tests(startup) {…}!sub setup : Tests(setup) {}!sub teardown : Tests(teardown) {}!sub shutdown : Tests(shutdown) {}!
1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
sub startup : Tests(startup) {! my $test = shift;! return if $test->class;!
my $class = ref $test;! $class =~ s/^TestsFor:://;!
eval "use $class";! die $@ if $@;!
$test->class($class);!}!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package Person; !
use Moose;!
has ‘first_name’ => ( is => 'ro', isa => 'Str' );!has ‘last_name’ => ( is => 'ro', isa => 'Str' );!
sub full_name {! my $self = shift;! return $self->first_name . ' ' ! . $self->last_name;!}!
1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;!
can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;! can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;! can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;! can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;! can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;! can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!
use Test::Class::Most parent =>'My::Test::Class';!
sub constructor : Tests(3) {! my $test = shift;! my $class = $test->class;! can_ok $class, 'new'; ! ok my $person = $class->new, ! '... and the constructor should succeed';! isa_ok $person, $class, ! '... and the object it returns';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
prove -lv -It/lib \! t/lib/TestsFor/Person.pm !
# INIT { Test::Class->runtests }!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
t/TestsFor/Person.pm .. # !# TestsFor::Person->constructor!
1..3!ok 1 - Person->can('new')!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa
Person!ok!All tests successful.!Files=1, Tests=3, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person;!Use Test::Class::Most parent => ‘My::Test::Class’;!sub constructor : Tests(3) { … }!
sub full_name : Tests(4) { ! my $test = shift;! my $person = $test->class->new(! first_name => 'Adrian',! last_name => 'Howard',! );!
is $person->first_name, 'Adrian', 'first_name correct';! is $person->last_name, 'Howard', 'last_name correct';!
can_ok $person, 'full_name';! is $person->full_name, 'Adrian Howard',! '... and it should return the correct fullname';!}!
1;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
$ prove –vl -It/lib t/TestsFor/Person.pm!t/TestsFor/Person.pm .. # !# TestsFor::Person->constructor!1..7!ok 1 - Person->can('new’)!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa Person!# !# TestsFor::Person->full_name!ok 4 - first_name correct!ok 5 - last_name correct!ok 6 - Person->can('full_name')!ok 7 - ... and it should return the correct fullname!ok!All tests successful.!Files=1, Tests=7, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package Person::Employee; !
use Moose;!extends 'Person';!
has ‘employee_number’ => ( ! is => ‘ro’, ! isa => ‘Int’,!);!
1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Person::Employee;!
use Test::Class::Most parent => 'TestsFor::Person';!
sub employee_number : Tests(2) { ! my $test = shift;! my $employee = $test->class->new(! first_name => 'John',! last_name => 'Public',! employee_number => 17,! );! can_ok $employee, 'employee_number’;! is $employee->employee_number, 17, ! '... the employee number is correct';!}!1;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
t/TestsFor/Person/Employee.pm .. # !# TestsFor::Person::Employee->constructor!
1..16!ok 1 - Person::Employee->can('new')!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa
Person::Employee!# !# TestsFor::Person::Employee->employee_number!ok 4 - Person::Employee-
>can('employee_number')!ok 5 - ... the employee number is correct!# !# TestsFor::Person::Employee->full_name!ok 6 - first_name correct!ok 7 - last_name correct!ok 8 - Person::Employee->can('full_name')!ok 9 - ... and it should return the correct
fullname!
# !# TestsFor::Person->constructor!ok 10 - Person->can('new')!ok 11 - ... and the constructor should
succeed!ok 12 - ... and the object it returns isa
Person!# !# TestsFor::Person->full_name!ok 13 - first_name correct!ok 14 - last_name correct!ok 15 - Person->can('full_name')!ok 16 - ... and it should return the correct
fullname!ok!All tests successful.!Files=1, Tests=16, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
t/TestsFor/Person/Employee.pm .. # !# TestsFor::Person::Employee->constructor!
1..16!ok 1 - Person::Employee->can('new')!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa
Person::Employee!# !# TestsFor::Person::Employee->employee_number!ok 4 - Person::Employee-
>can('employee_number')!ok 5 - ... the employee number is correct!# !# TestsFor::Person::Employee->full_name!ok 6 - first_name correct!ok 7 - last_name correct!ok 8 - Person::Employee->can('full_name')!ok 9 - ... and it should return the correct
fullname!
# !# TestsFor::Person->constructor!ok 10 - Person->can('new')!ok 11 - ... and the constructor should
succeed!ok 12 - ... and the object it returns isa
Person!# !# TestsFor::Person->full_name!ok 13 - first_name correct!ok 14 - last_name correct!ok 15 - Person->can('full_name')!ok 16 - ... and it should return the correct
fullname!ok!All tests successful.!Files=1, Tests=16, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
t/TestsFor/Person/Employee.pm .. # !# TestsFor::Person::Employee->constructor!
1..16!ok 1 - Person::Employee->can('new')!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa
Person::Employee!# !# TestsFor::Person::Employee->employee_number!ok 4 - Person::Employee-
>can('employee_number')!ok 5 - ... the employee number is correct!# !# TestsFor::Person::Employee->full_name!ok 6 - first_name correct!ok 7 - last_name correct!ok 8 - Person::Employee->can('full_name')!ok 9 - ... and it should return the correct
fullname!
# !# TestsFor::Person->constructor!ok 10 - Person->can('new')!ok 11 - ... and the constructor should
succeed!ok 12 - ... and the object it returns isa
Person!# !# TestsFor::Person->full_name!ok 13 - first_name correct!ok 14 - last_name correct!ok 15 - Person->can('full_name')!ok 16 - ... and it should return the correct
fullname!ok!All tests successful.!Files=1, Tests=16, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
t/TestsFor/Person/Employee.pm .. # !# TestsFor::Person::Employee->constructor!
1..16!ok 1 - Person::Employee->can('new')!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa
Person::Employee!# !# TestsFor::Person::Employee->employee_number!ok 4 - Person::Employee-
>can('employee_number')!ok 5 - ... the employee number is correct!# !# TestsFor::Person::Employee->full_name!ok 6 - first_name correct!ok 7 - last_name correct!ok 8 - Person::Employee->can('full_name')!ok 9 - ... and it should return the correct
fullname!
# !# TestsFor::Person->constructor!ok 10 - Person->can('new')!ok 11 - ... and the constructor should
succeed!ok 12 - ... and the object it returns isa
Person!# !# TestsFor::Person->full_name!ok 13 - first_name correct!ok 14 - last_name correct!ok 15 - Person->can('full_name')!ok 16 - ... and it should return the correct
fullname!ok!All tests successful.!Files=1, Tests=16, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
t/TestsFor/Person/Employee.pm .. # !# TestsFor::Person::Employee->constructor!
1..16!ok 1 - Person::Employee->can('new')!ok 2 - ... and the constructor should succeed!ok 3 - ... and the object it returns isa
Person::Employee!# !# TestsFor::Person::Employee->employee_number!ok 4 - Person::Employee-
>can('employee_number')!ok 5 - ... the employee number is correct!# !# TestsFor::Person::Employee->full_name!ok 6 - first_name correct!ok 7 - last_name correct!ok 8 - Person::Employee->can('full_name')!ok 9 - ... and it should return the correct
fullname!
# !# TestsFor::Person->constructor!ok 10 - Person->can('new')!ok 11 - ... and the constructor should
succeed!ok 12 - ... and the object it returns isa
Person!# !# TestsFor::Person->full_name!ok 13 - first_name correct!ok 14 - last_name correct!ok 15 - Person->can('full_name')!ok 16 - ... and it should return the correct
fullname!ok!All tests successful.!Files=1, Tests=16, 0 wallclock secs!Result: PASS!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
sub startup : Tests(startup) {! my $test = shift;! return if $test->class;!
my $class = ref $test;! $class =~ s/^TestsFor:://;!
eval "use $class";! die $@ if $@;!
$test->class($class);!}!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
TestsFor::Person::Employee inherits TestsFor::Person’s tests
We don’t hard-code the class name Inherited test methods rock!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Attribute Name Phase
Tests(startup)! When the test class starts
Tests(setup)! Before each test method
Tests(teardown)! After each test method
Tests(shutdown)! When the test class finishes
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Connect to a database (often in startup) Set up fixtures/transactions (setup) Clean fixtures/rollbacks (teardown) Disconnect from database (shutdown) (They’re a better place for object construction)
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Customer;!
use Test::Class::Most! parent => ‘My::Test::Class’,! attributes => [‘dbh’];!
sub aaa_connect_to_db : Tests(setup) {! my $test = shift;! my $dbh = DBI->connect(…);! # or $test->{dbh} = $dbh;! $test->dbh($dbh);!}!
sub some_test : Tests {! my $test = shift;! my $dbh = $test->dbh;!…!
package TestsFor::Person::Employee;!
use Test::Class::Most! parent => ‘TestsFor::Customer’,! attributes => [‘employee’];!
sub bbb_employee : Tests(setup) {! my $test = shift;! my $employee = $test->dbh->…;! $test->employee($employee);!}!
sub kill_employee : Tests {! my $test = shift;! my $employee = $test->employee;! can_ok( $employee, ‘suffocate’ );!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Customer;!
use Test::Class::Most! parent => ‘My::Test::Class’,! attributes => [‘dbh’];!
sub aaa_connect_to_db : Tests(setup) {! my $test = shift;! my $dbh = DBI->connect(…);! # or $test->{dbh} = $dbh;! $test->dbh($dbh);!}!
sub some_test : Tests {! my $test = shift;! my $dbh = $test->dbh;!…!
package TestsFor::Person::Employee;!
use Test::Class::Most! parent => ‘TestsFor::Customer’,! attributes => [‘employee’];!
sub bbb_employee : Tests(setup) {! my $test = shift;! my $employee = $test->dbh->…;! $test->employee($employee);!}!
sub kill_employee : Tests {! my $test = shift;! my $employee = $test->employee;! can_ok( $employee, ‘suffocate’ );!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
package TestsFor::Customer;!
use Test::Class::Most! parent => ‘My::Test::Class’,! attributes => [‘dbh’];!
sub setup : Tests(setup) {! my $test = shift;! my $dbh = DBI->connect(…);! # or $test->{dbh} = $dbh;! $test->dbh($dbh);!}!
sub some_test : Tests {! my $test = shift;! my $dbh = $test->dbh;!…!
package TestsFor::Person::Employee;!
use Test::Class::Most! parent => ‘TestsFor::Customer’,! attributes => [‘employee’];!
sub setup : Tests(setup) {! my $test = shift;! $test->SUPER::setup;! my $employee = $test->dbh->…;! $test->employee($employee);!}!
sub kill_employee : Tests {! my $test = shift;! my $employee = $test->employee;! can_ok( $employee, ‘suffocate’ );!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Before Tests
sub startup:Test(startup) {! my $test = shift;! $test->SUPER::startup;! # finish your startup!}!
sub setup : Test(setup) {! my $test = shift;! $test->SUPER::setup;! # finish your setup!}!
After Tests
sub teardown:Test(teardown){! my $test = shift;! # finish your teardown! $test->SUPER::teardown;!}!
sub shutdown:Test(shutdown){! my $test = shift;! # finish your shutdown! $test->SUPER::shutdown;!}!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
# t/test_class_tests.t!# Don’t Do This!!use lib ‘t/lib’;!
use TestsFor::Person;!use TestsFor::Person::Employee;!
Test::Class->runtests;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
# Don’t Do This because you’ll forget one!!use lib ‘t/lib’;!use TestsFor::Person;!use TestsFor::Person::Employee;!use TestsFor::Database;!use TestsFor::PurchaseOrder;!use TestsFor::Alibi;!use TestsFor::Embezzlement;!use TestsFor::PaddingMySlides;!Test::Class->runtests;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
# Do This!!use Test::Class::Load ‘t/lib’;!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Finds your test classes for you My example relies on
INIT { Test::Class->runtests } in My::Test::Class.
Run the test suite: prove -l t/test_class_tests.t!
Or a single test class: prove -lv -It/lib t/TestsFor/Person.pm
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Name test classes after their classes (if possible) Name test methods after their methods (if possible) … you can’t name a method new()! Create your own base test class … with stub test control methods Name test control methods after their attribute Don’t put tests in your test control methods Do not hardcode the name of the class to test!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Part 1: Getting started with Test::Class Part 2: Inheriting Test::Class tests Part 3: Making your testing life easier Part 4: Using test control methods Part 5: Test::Class Tricks
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
Beginning Perl, Wrox Press Introduction to Perl CPAN Modules Objects (Moose!) Testing PSGI+Plack DBIx::Class Catalyst And more!
http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass