A Whirlwind Tour of Test::Class

13,656 views

Published on

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

  • Be the first to like this

No Downloads
Views
Total views
13,656
On SlideShare
0
From Embeds
0
Number of Embeds
11,202
Actions
Shares
0
Downloads
18
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Single versus multiple processesTests that don’t map to classesDetailed testing strategiesWhy some of this presentation works
  • A Whirlwind Tour of Test::Class

    1. 1.   OO tests for OO code   Nice performance boost   Easy-to-organize test suiteshttp://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    2. 2.   Plenty!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    3. 3. 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
    4. 4. use Test::Class::Most! parent => My::Test::Class’;! sub some_test : Tests { ... }!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    5. 5. 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
    6. 6. 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
    7. 7. 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
    8. 8. 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
    9. 9. 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
    10. 10. 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
    11. 11. 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
    12. 12. 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
    13. 13. 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
    14. 14. 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
    15. 15. 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
    16. 16. 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
    17. 17. 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
    18. 18. 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
    19. 19. prove -lv -It/lib ! t/lib/TestsFor/Person.pm ! # INIT { Test::Class->runtests }!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    20. 20. 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
    21. 21. 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
    22. 22. $ 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
    23. 23. 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
    24. 24. 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
    25. 25. t/TestsFor/Person/Employee.pm .. # ! # ! # TestsFor::Person::Employee->constructor! # TestsFor::Person->constructor! ok 10 - Person->can(new)! 1..16! ok 11 - ... and the constructor should ok 1 - Person::Employee->can(new)! succeed! ok 2 - ... and the constructor should succeed! ok 12 - ... and the object it returns isa ok 3 - ... and the object it returns isa Person! Person::Employee! # ! # ! # TestsFor::Person->full_name! # TestsFor::Person::Employee->employee_number! ok 13 - first_name correct! ok 4 - Person::Employee- ok 14 - last_name correct! >can(employee_number)! ok 15 - Person->can(full_name)! ok 5 - ... the employee number is correct! ok 16 - ... and it should return the correct # ! fullname! # TestsFor::Person::Employee->full_name! ok! ok 6 - first_name correct! All tests successful.! ok 7 - last_name correct! Files=1, Tests=16, 0 wallclock secs! ok 8 - Person::Employee->can(full_name)! Result: PASS! ok 9 - ... and it should return the correct fullname!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    26. 26. t/TestsFor/Person/Employee.pm .. # ! # ! # TestsFor::Person::Employee->constructor! # TestsFor::Person->constructor! ok 10 - Person->can(new)! 1..16! ok 11 - ... and the constructor should ok 1 - Person::Employee->can(new)! succeed! ok 2 - ... and the constructor should succeed! ok 12 - ... and the object it returns isa ok 3 - ... and the object it returns isa Person! Person::Employee! # ! # ! # TestsFor::Person->full_name! # TestsFor::Person::Employee->employee_number! ok 13 - first_name correct! ok 4 - Person::Employee- ok 14 - last_name correct! >can(employee_number)! ok 15 - Person->can(full_name)! ok 5 - ... the employee number is correct! ok 16 - ... and it should return the correct # ! fullname! # TestsFor::Person::Employee->full_name! ok! ok 6 - first_name correct! All tests successful.! ok 7 - last_name correct! Files=1, Tests=16, 0 wallclock secs! ok 8 - Person::Employee->can(full_name)! Result: PASS! ok 9 - ... and it should return the correct fullname!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    27. 27. t/TestsFor/Person/Employee.pm .. # ! # ! # TestsFor::Person::Employee->constructor! # TestsFor::Person->constructor! ok 10 - Person->can(new)! 1..16! ok 11 - ... and the constructor should ok 1 - Person::Employee->can(new)! succeed! ok 2 - ... and the constructor should succeed! ok 12 - ... and the object it returns isa ok 3 - ... and the object it returns isa Person! Person::Employee! # ! # ! # TestsFor::Person->full_name! # TestsFor::Person::Employee->employee_number! ok 13 - first_name correct! ok 4 - Person::Employee- ok 14 - last_name correct! >can(employee_number)! ok 15 - Person->can(full_name)! ok 5 - ... the employee number is correct! ok 16 - ... and it should return the correct # ! fullname! # TestsFor::Person::Employee->full_name! ok! ok 6 - first_name correct! All tests successful.! ok 7 - last_name correct! Files=1, Tests=16, 0 wallclock secs! ok 8 - Person::Employee->can(full_name)! Result: PASS! ok 9 - ... and it should return the correct fullname!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    28. 28. t/TestsFor/Person/Employee.pm .. # ! # ! # TestsFor::Person::Employee->constructor! # TestsFor::Person->constructor! ok 10 - Person->can(new)! 1..16! ok 11 - ... and the constructor should ok 1 - Person::Employee->can(new)! succeed! ok 2 - ... and the constructor should succeed! ok 12 - ... and the object it returns isa ok 3 - ... and the object it returns isa Person! Person::Employee! # ! # ! # TestsFor::Person->full_name! # TestsFor::Person::Employee->employee_number! ok 13 - first_name correct! ok 4 - Person::Employee- ok 14 - last_name correct! >can(employee_number)! ok 15 - Person->can(full_name)! ok 5 - ... the employee number is correct! ok 16 - ... and it should return the correct # ! fullname! # TestsFor::Person::Employee->full_name! ok! ok 6 - first_name correct! All tests successful.! ok 7 - last_name correct! Files=1, Tests=16, 0 wallclock secs! ok 8 - Person::Employee->can(full_name)! Result: PASS! ok 9 - ... and it should return the correct fullname!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    29. 29. t/TestsFor/Person/Employee.pm .. # ! # ! # TestsFor::Person::Employee->constructor! # TestsFor::Person->constructor! ok 10 - Person->can(new)! 1..16! ok 11 - ... and the constructor should ok 1 - Person::Employee->can(new)! succeed! ok 2 - ... and the constructor should succeed! ok 12 - ... and the object it returns isa ok 3 - ... and the object it returns isa Person! Person::Employee! # ! # ! # TestsFor::Person->full_name! # TestsFor::Person::Employee->employee_number! ok 13 - first_name correct! ok 4 - Person::Employee- ok 14 - last_name correct! >can(employee_number)! ok 15 - Person->can(full_name)! ok 5 - ... the employee number is correct! ok 16 - ... and it should return the correct # ! fullname! # TestsFor::Person::Employee->full_name! ok! ok 6 - first_name correct! All tests successful.! ok 7 - last_name correct! Files=1, Tests=16, 0 wallclock secs! ok 8 - Person::Employee->can(full_name)! Result: PASS! ok 9 - ... and it should return the correct fullname!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    30. 30. 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
    31. 31.   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
    32. 32. 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 finisheshttp://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    33. 33.   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
    34. 34. package TestsFor::Customer;! package TestsFor::Person::Employee;! use Test::Class::Most! use Test::Class::Most! parent => ‘My::Test::Class’,! parent => ‘TestsFor::Customer’,! attributes => [‘dbh’];! attributes => [‘employee’];! sub aaa_connect_to_db : Tests(setup) {! sub bbb_employee : Tests(setup) {! my $test = shift;! my $test = shift;! my $dbh = DBI->connect(…);! my $employee = $test->dbh->…;! # or $test->{dbh} = $dbh;! $test->employee($employee);! $test->dbh($dbh);! }! }! sub kill_employee : Tests {! sub some_test : Tests {! my $test = shift;! my $test = shift;! my $employee = $test->employee;! my $dbh = $test->dbh;! can_ok( $employee, ‘suffocate’ );! …!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    35. 35. package TestsFor::Customer;! package TestsFor::Person::Employee;! use Test::Class::Most! use Test::Class::Most! parent => ‘My::Test::Class’,! parent => ‘TestsFor::Customer’,! attributes => [‘dbh’];! attributes => [‘employee’];! sub aaa_connect_to_db : Tests(setup) {! sub bbb_employee : Tests(setup) {! my $test = shift;! my $test = shift;! my $dbh = DBI->connect(…);! my $employee = $test->dbh->…;! # or $test->{dbh} = $dbh;! $test->employee($employee);! $test->dbh($dbh);! }! }! sub kill_employee : Tests {! sub some_test : Tests {! my $test = shift;! my $test = shift;! my $employee = $test->employee;! my $dbh = $test->dbh;! can_ok( $employee, ‘suffocate’ );! …!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    36. 36. package TestsFor::Customer;! package TestsFor::Person::Employee;! use Test::Class::Most! use Test::Class::Most! parent => ‘My::Test::Class’,! parent => ‘TestsFor::Customer’,! attributes => [‘dbh’];! attributes => [‘employee’];! sub setup : Tests(setup) {! sub setup : Tests(setup) {! my $test = shift;! my $test = shift;! my $dbh = DBI->connect(…);! $test->SUPER::setup;! # or $test->{dbh} = $dbh;! my $employee = $test->dbh->…;! $test->dbh($dbh);! $test->employee($employee);! }! }! sub some_test : Tests {! sub kill_employee : Tests {! my $test = shift;! my $test = shift;! my $dbh = $test->dbh;! my $employee = $test->employee;! …! can_ok( $employee, ‘suffocate’ );!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    37. 37. Before Tests After Tests sub startup:Test(startup) {! sub teardown:Test(teardown){! my $test = shift;! my $test = shift;! $test->SUPER::startup;! # finish your teardown! # finish your startup! $test->SUPER::teardown;! }! }! sub setup : Test(setup) {! sub shutdown:Test(shutdown){! my $test = shift;! my $test = shift;! $test->SUPER::setup;! # finish your shutdown! # finish your setup! $test->SUPER::shutdown;! }! }!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    38. 38. # 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
    39. 39. # 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
    40. 40. # Do This!! use Test::Class::Load ‘t/lib’;!http://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    41. 41.   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.pmhttp://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    42. 42.   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
    43. 43.   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 Trickshttp://www.slideshare.net/Ovid/a-whirlwind-tour-of-testclass
    44. 44.   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

    ×