Results tagged “test::class”

Tests are Code Too!

Of all of the frustrating debates in software development, bickering over the value of automated testing confuses me the most. I can understand why people who've never tried pair programming seriously have doubts about it. I can even understand why people who know nothing about programming or construction think that designing a building is like designing software.

I don't understand programmers who think automated testing isn't all that useful because tests can be difficult to maintain.

Perl's testing culture had its renaissance when several of us realized that people saw testing as confusing black magic. (No joke; the "copy and paste this header into all of your test files!" generated by h2xs in test.pl used to say "black magic here" before four lines of gobbledegook.)

The nice thing about a renaissance is that you can clear away confusing, magical thinking and replace it with bright, understandable foundations for grander, more elegant, more powerful, and futureful thought.

This occurred on two levels. First, the parallel development of Test::Simple and Test::More made two libraries that were almost trivially easy to understand. Writing good tests requires skill and experience, but writing tests at all requires two minutes of reading and experimenting. The path to mastery begins not with copying and pasting black magic gobbledegook that explicitly warns you off of understanding it but by saying what you mean to say.

Another part of that was good initial design of what would become TAP way back in 1987, as well as other parts of the toolchain, but removing the initial barrier to starting was a huge improvement.

The other foot of the renaissance was Test::Builder. You can start with Test::More and use it productively... but if you're not careful, you'll end up with long, procedural test files with a lot of duplication.

Test::Builder exists solely to remove duplication. It's a foundational library for the abstraction of tests and test structures. You can see this in Testing with Test::Class. You don't necessarily have to write your own testing modules to take advantage of this possibility; the CPAN has hundreds of Test::* modules for your own use.

That's what modern Perl programmers do. We solve problems, then we make the solutions available. We'd never have achieved this for our tests if we hadn't realized the simple, fundamental fact of automated tests: they're just code. All of the good habits you have for managing code apply to managing tests.

That includes choosing the proper libraries and abstractions.

Working with Test::Class Test Suites

In this series, I've explained how to use Test::Class in Perl, how to reuse Test::Class tests, and how to simplify Test::Class tests, and how to manage data dependencies and fixtures with Test::Class tests. If you've followed along -- and if you've written your own tests with Test::Class, you're on your way to becoming a testing expert. Now it's time to discuss some ancillary issues you may encounter.

Performance

With Test::Class::Load, you can run all of your test class tests in one process:

     use Test::Class::Load qw<path/to/tests>;

That loads the tests and all modules you're testing once. This can be a huge performance boost if you're loading "heavy" modules such as Catalyst or DBIx::Class. However, be aware that you're now loading all classes in a single process; there are potential drawbacks here. For example, if one of your classes alters a singleton or global variable that another class depends on, you may get unexpected results. Also, many classes load modules which globally alter Perl's behavior. Grep through your CPAN modules for UNIVERSAL:: or CORE::GLOBAL:: to see just how many classes do this.

Global state changes can introduce difficult-to-diagnose bugs. You will have to decide for yourself whether the benefits of Test::Class outweigh these drawbacks. My experience is that these bugs are usually very painful to resolve, but in finding them, I often find intermittant problems in my code bases that I could not have found any other way. For me, Test::Class offers many benefits, despite occasional frustrations.

People who prefer not to run all of their code in a single process often create separate "driver" tests:

     #!/usr/bin/env perl -T

     use Test::Person;
     Test::Class->runtests;

... and:

     #!/usr/bin/env perl -T

     use Test::Person::Employee;
     Test::Class->runtests;

Remember to omit the call to runtests if you've included this in your base class INIT.

Making Your Classes Behave Like xUnit Classes

In xUnit style tests, this is an entire test:

     sub first_name : Tests(tests => 3) {
         my $test   = shift;
         my $person = $test->class->new;

         can_ok $person, 'first_name';
         ok !defined $person->first_name,
           '... and first_name should start out undefined';

         $person->first_name('John');
         is $person->first_name, 'John', '... and setting its value should succeed';
     }

The TAP world considers this as three tests, but xUnit regards these three assertions as validations of a single feature, and thus one test. TAP-based tests have a long way to go before working for xUnit users, but there's one thing we can do. Suppose that you have a test with 30 asserts. The fourth assert fails. Many xUnit programmers argue that once an assert fails, the rest of the information in the test is unreliable. In that case, the test driver often halts. Regardless of whether you agree (I hate that JUnit requires the test method to stop), you can get this behavior with Test::Class. Use Test::Most instead of Test::More and put this in your test base class:

    BEGIN { $ENV{DIE_ON_FAIL} = 1 }

Because each test method in Test::Class is wrapped in an eval, that test method will stop running, the appropriate teardown method (if any) will execute and the tests will resume with the next test method.

I'm not a huge fan of this technique, but your mileage may vary.

Conclusion

While many projects work just fine using simple Test::More programs, larger projects can wind up with scalability problems. Test::Class gives you better opportunities for managing your tests, refactoring common code, and having your test code better mirror your production code.

Here's a quick summary of tips in this series:

  • Name your test classes consistently after the classes they're testing.
  • When possible, do the same for your test methods.
  • Don't use a constructor test named new.
  • Create your own Test::Class base class.
  • Abstract the the name of the class you're testing into a class method in your base class.
  • Name test control methods after their attribute.
  • Decide case-by-case whether to call a control method's parent method.
  • Don't put tests in your test control methods.

Acknowledgments

Thanks to Adrian Howard for creating the Test::Class module and providing me with tips in making it easier to use. Also, David Wheeler provided some useful comments, but that was on a first draft written years ago. I wonder if he remembers?

Using Test Control Methods with Test::Class

Handling Startup/Setup/Teardown/Shutdown Methods

When you understand Organizing Test Suites with Test::Class, Reusing Test Code with Test::Class, and Removing Boilerplate Testing Code, you'll likely to discover that you need to have special code run at the start and end of a class and at the start and end of every test method. This code might connect to databases, delete temp files, or set up test fixtures.

Test::Class provides four test control methods to help:

  • startup
  • This method runs once for each class, before any tests run.

  • shutdown
  • This method runs once for each class, after all tests have run.

  • setup
  • This method runs before each test method.

  • teardown
  • This method runs after each test method.

startup and shutdown

One common function for the startup and shutdown methods is to set up and tear down a database:

     package Tests::My::Resultset::Customer;

     use base 'My::Test::Class';

     sub startup : Tests(startup) {
         my $test = shift;
         $test->_connect_to_database;
     }

     sub shutdown : Tests(shutdown) {
         my $test = shift;
         $test->_disconnect_from_database;
     }

     ...

When the test class loads, the first code which Test::Class runs is startup. At the end of the test, Test::Class calls the shutdown method is called and we disconnect from the database. Note that if the startup method has any tests and one fails, or if it throws any exception, the rest of the tests will not run. Any tests for parent classes will still run.

     sub startup : Tests(startup) {
         ok 0;   # the test class will abort here
     }

If this occurs, the shutdown method will not be called.

setup and teardown

It can also be useful to run code before and after every test method. Here's how:

     sub setup : Tests(setup) {
         my $test = shift;
         $test->_start_db_transaction;
     }

     sub check_priviledges : Tests(no_plan) {
         my $test = shift;
         $test->_load_priviledge_fixture;
         ...
     }

     sub teardown : Tests(teardown) {
         my $test = shift;
         $test->_rollback_db_transaction;
     }

This code starts a database transaction before every test method. The check_priviledges method loads its own test fixture and the teardown method rolls back the transaction, ensuring that the next test will have a pristine database. Note that if the setup method fails a test, the teardown method will still be called. This is different behavior for the startup method because Test::Class moves on to the next test and assumes you still want to continue.

Overriding test control methods

Users new to Test::Class often find that they run more test control methods than they expected or their test control methods run in an order they did not expect.

Controlling order of execution

Suppose that your test base class contains:

     sub connect_to_db : Tests(startup) {
         my $test = shift;
         $test->_connect_to_db;
     }

A test subclass contains:

     sub assert_db : Tests(startup => 1) {
         my $test = shift;
         ok $test->_is_connected_to_db, 'We still have a database connection';
     }

That will probably fail and your tests will not run. Why? Test::Class runs tests in alphabetical order in a test class. Because it includes inherited tests in your test class, you've inherited connect_to_db. As that sorts after assert_db, it runs after assert_db. Thus, you're asserting your database connection before you've connected.

The problem is tightly-coupled methods which rely on execution order. The fix is simple. Rename both startup methods to startup and have the child class call the super class method:

     sub startup : Tests(startup) {
         my $test = shift;
         $test->SUPER::startup;
         die unless $test->_is_connected_to_db, 'We still have a database connection';
     }

This works because Test::Class knows you've overridden the method and you can call it manually.

Warning: Note that the startup method now dies rather than running a test. Test::Class has no way of knowing if you're really going to call the super class. As a result, it has no way of knowing the real test count. The die halts the startup method.

Tip: for reasons mentioned above, don't put tests in your test control methods.

Controlling what gets executed

Suppose that you've a web page which provides additional features to authenticated users. You might test it with:

     sub unauthenticated_startup : Test(startup) {
         my $test = shift;
         $test->_connect_as_unauthenticated;
     }

In your "authenticated" subclass, you may have:

     sub authenticated_startup : Test(startup) {
         my $test = shift;
         $test->_connect_as_authenticated;
     }

Again, your tests will probably fail because authenticated_startup will run before unauthenticated_startup, and you have probably connected as the unauthenticated user in your "authenticated" subclass. However, this time you probably don't even need unauthenticated_startup to run. The solution is again to give the tests the same name without calling the parent's method:

     sub startup : Test(startup) {
         my $test = shift;
         $test->_connect_as_authenticated;
     }

Note that this control method does not run tests. If the connection fails, throw an exception.

The next and final article in this series explains how to manage test suites with Test::Class.

Making Your Testing Life Easier

After absorbing the information in Organizing Test Suites with Test::Class and Reusing Test Code with Test::Class, you're probably beginning to understand how Test::Class can make managing large codebases easier. If you've worked with test cases before, you've likely realized that test code is still code. Well-organized test code is easier to work with than poorly organized test code.

Auto-discovering your test classes

There's too much repetitive boilerplate in these tests. We can make them easier. The first problem is the helper script, t/run.t:

     #!/usr/bin/env perl -T

     use lib 't/tests';

     use Test::Person;
     use Test::Person::Employee;

     Test::Class->runtests;

Right now, this doesn't look so bad, but as you start to add more classes, this gets to be unwieldy. What if you forget to add a test class? Your class might be broken, but if the test class does not run, how will you know? Autodiscovering test classes helps:

     #!/usr/bin/env perl -T

     use Test::Class::Load qw<t/tests>;
     Test::Class->runtests;

Tell Test::Class::Load (bundled with Test::Class) which directories your test classes are in and it will find them for you. It does this by loading attempting to load all files with a .pm extension, so keep any helper test modules (which are not Test::Class tests) in a separate directory.

Using a common base class

Another useful technique of programming in general is to factor out common code. I've demonstrated this already, but there's room for improvement. Both test classes have a method for returning the name of the class being tested. It's possible to compute the name of this class, so why not push this into a base class? Add this to t/tests/My/Test/Class.pm:

     package My::Test::Class;

     use Test::Most;
     use base qw<Test::Class Class::Data::Inheritable>;

     BEGIN {
         __PACKAGE__->mk_classdata('class');
     }

     sub startup : Tests( startup => 1 ) {
         my $test = shift;
         ( my $class = ref $test ) =~ s/^Test:://;
         return ok 1, "$class loaded" if $class eq __PACKAGE__;
         use_ok $class or die;
         $test->class($class);
     }

     1;

In Person::Employee, delete the class method. In Person, delete the class and startup methods, and inherit from My::Test::Class instead of Test::Class. Now, class will always return the current class under testing. The new Test::Person class looks like:

     package Test::Person;

     use Test::Most;
     use base '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';
     }

     sub first_name : Tests(3) {
         my $test   = shift;
         my $person = $test->class->new;

         can_ok $person, 'first_name';
         ok !defined $person->first_name,
           '... and first_name should start out undefined';

         $person->first_name('John');
         is $person->first_name, 'John', '... and setting its value should succeed';
     }

     sub last_name : Tests(3) {
         my $test   = shift;
         my $person = $test->class->new;

         can_ok $person, 'last_name';
         ok !defined $person->last_name,
           '... and last_name should start out undefined';

         $person->last_name('Public');
         is $person->last_name, 'Public', '... and setting its value should succeed';
     }

     sub full_name : Tests(4) {
         my $test   = shift;
         $test->_full_name_validation;

         my $person = $test->class->new(
             first_name => 'John',
             last_name  => 'Public',
         );

         is $person->full_name, 'John Public',
           '... and setting its value should succeed';
     }

     sub _full_name_validation {
         my ( $test, $person ) = @_;
         my $person = $test->class->new;
         can_ok $person, 'full_name';

         throws_ok { $person->full_name }
             qr/^Both first and last names must be set/,
             '... and full_name() should croak() if the either name is not set';

         $person->first_name('John');

         throws_ok { $person->full_name }
             qr/^Both first and last names must be set/,
             '... and full_name() should croak() if the either name is not set';
     }

     1;

The test results for Test::Person::Employee are:

     All tests successful.
     Files=1, Tests=32,  1 wallclock secs ( 0.33 cusr +  0.08 csys =  0.41 CPU)

There's an extra test, due to the ok 1 found in the My::Test::Class::startup method. It gets called an extra time for the loading of My::Test::Class.

Tip: If you must load your at BEGIN time, override this startup method in your test class -- but be sure to provide a class method.

Run individual test classes

When I develop tests, I hate to leave my editor merely to run tests from the command line. To avoid this, I a mapping in my .vimrc file similar to:

      noremap ,t :!prove --merge -lv %<CR>

When writing tests, I hit ,t and my test runs. However, doing this in a test class doesn't work. The class gets loaded, but the tests do not run. I could add a new mapping:

      noremap ,T  :!prove -lv --merge t/run.t<CR>

... but this runs all of my test classes. If I have several hundred tests, I don't want to hunt back through all of the test output to see which tests failed. Instead, I want to run a single test class. I altered my mapping to include the path to my test classes.

      noremap ,t  :!prove -lv --merge -It/tests %<CR>

I also removed the Test::Class->runtests line from t/run.t (or else I'll have my tests run twice if I run the full test suite). Because I use a common base class, I added a line to My::Test::Class:

      INIT { Test::Class->runtests }

Regardless of whether I'm in a standard Test::Most test program or one of my new test classes, I can type ,t and run only the tests in the file I'm editing.

If you run the tests for Test::Person::Employee, you'll see the full run of 32 tests because Test::Class will run the tests for the current class and all classes from which it inherits. If you run the tests for Test::Person, you'll only see 15 tests run -- the desired behavior.

If you prefer Emacs, add this to your ~/.emacs file:

     (eval-after-load "cperl-mode"
         '(add-hook 'cperl-mode-hook
             (lambda () (local-set-key "\C-ct" 'cperl-prove))))

     (defun cperl-prove ()
         "Run the current test."
         (interactive)
         (shell-command (concat "prove -lv --merge -It/tests "
             (shell-quote_argument (buffer-file-name)))))

That will bind this to C-c t and you can pretend that you're as cool as Vim users (just kidding! Stop the hate mail already).

Next time, learn to use test control methods with Test::Class.

Reusing Test Code with Test::Class

After reading Organizing Test Suites with Test::Class, you're probably and saying "that's a heck of a lot of work just for testing a class." If this were all there is to it, you'd be perfectly justified in forgetting about Test::Class. However, Test::Class really shines when it comes to code re-use. Consider writing a subclass of Person named Person::Employee. I'll keep it simple by only providing an employee_number method, but you'll quickly understand the benefits.

     package Person::Employee;

     use Moose;
     extends 'Person';

     has employee_number => ( is => 'rw', isa => 'Int' );

     1;

Here's its test class:

     package Test::Person::Employee;

     use Test::Most;
     use base 'Test::Person';

     sub class {'Person::Employee'}

     sub employee_number : Tests(3) {
         my $test     = shift;
         my $employee = $test->class->new;

         can_ok $employee, 'employee_number';
         ok !defined $employee->employee_number,
             '... and employee_number should not start out defined';

         $employee->employee_number(4);
         is $employee->employee_number, 4,
             '... but we should be able to set its value';
     }

     1;

Notice that instead of inheriting from Test::Class, the test inherits from Test::Person, just like Person::Employee class inherited from Person. Also, this overrides the class method to ensure that tests know which class they're using.

Remember to add Test::Person::Employee to t/run.t:

     #!/usr/bin/env perl -T

     use lib 't/tests';

     use Test::Person;
     use Test::Person::Employee;

     Test::Class->runtests;

    And when we run it t/run.t:

     All tests successful.
     Files=1, Tests=31,  1 wallclock secs ( 0.25 cusr +  0.06 csys =  0.31 CPU)

Whoa! Wait a minute. This new test class only had three tests. The previous run ran with 14, so how come the report says it ran 31?

Test::Person::Employee inherited the tests from Test::Person. The 14 original tests plus the 14 inherited tests and the 3 added tests add up to 31 tests! These aren't frivolous tests, either. Look at the new test's output:

     # Test::Person::Employee->constructor
     ok 16 - Person::Employee->can('new')
     ok 17 - ... and the constructor should succeed
     ok 18 - ... and the object it returns isa Person::Employee
     #
     # Test::Person::Employee->employee_number
     ok 19 - Person::Employee->can('employee_number')
     ok 20 - ... and employee_number should not start out defined
     ok 21 - ... but we should be able to set its value
     #
     # Test::Person::Employee->first_name
     ok 22 - Person::Employee->can('first_name')
     ok 23 - ... and first_name should start out undefined
     ok 24 - ... and setting its value should succeed
     #
     # Test::Person::Employee->full_name
     ok 25 - Person::Employee->can('full_name')
     ok 26 - ... and full_name() should croak() if the either name is not set
     ok 27 - ... and full_name() should croak() if the either name is not set
     ok 28 - ... and setting its value should succeed
     #
     # Test::Person::Employee->last_name
     ok 29 - Person::Employee->can('last_name')
     ok 30 - ... and last_name should start out undefined
     ok 31 - ... and setting its value should succeed

By not explicitly hard-coding the class name in the tests and because Test::Person::Employee had overridden the class method, these new tests run against instances of Person::Employee, not Person. This demonstrates that subclassing did not break any of the inherited behavior! However, if you do need to alter the behavior of one of those methods, as you might expect with object-oriented code, all you need to do is override the corresponding test method. For example, what if employees must have their full names listed in the format "last name, first name"?

     sub full_name {
         my $self = shift;

         unless ( $self->first_name && $self->last_name ) {
             Carp::croak("Both first and last names must be set");
         }

         return $self->last_name . ', ' . $self->first_name;
     }

The appropriate test method in Test::Person::Employee might look like:

     sub full_name : Tests(no_plan) {
         my $test   = shift;
         my $person = $test->class->new;
         can_ok $person, 'full_name';

         throws_ok { $person->full_name }
         qr/^Both first and last names must be set/,
           '... and full_name() should croak() if the either name is not set';

         $person->first_name('John');

         throws_ok { $person->full_name }
         qr/^Both first and last names must be set/,
           '... and full_name() should croak() if the either name is not set';

         $person->last_name('Public');
         is $person->full_name, 'Public, John',
           '... and setting its value should succeed';
     }

Make those changes and all tests will pass. Test::Person::Employee will call its own full_name test method and not that of its parent class.

Refactoring test classes

There's a lot of duplication in the full_name test which you should factor out into common code. The well-known (if poorly-practiced) aphorism that test code is just code is even more true when Test::Class. Well-factored tests are easier to understand, to maintain, and to modify than poorly-factored tests.

Refactoring with methods

One approach to reduce duplication in Test::Person class might be to create helper methods:

     sub full_name : Tests(no_plan)
         my $test   = shift;
         $test->_full_name_validation;

         my $person = $test->class->new(
             first_name => 'John',
             last_name  => 'Public',
         );

         is $person->full_name, 'John Public',
           'The name of a person should render correctly';
     }

     sub _full_name_validation {
         my ( $test, $person ) = @_;
         my $person            = $test->class->new;
         can_ok $person, 'full_name';

         throws_ok { $person->full_name }
             qr/^Both first and last names must be set/,
             '... and full_name() should croak() if the either name is not set';

         $person->first_name('John');

         throws_ok { $person->full_name }
             qr/^Both first and last names must be set/,
             '... and full_name() should croak() if the either name is not set';
     }

And in Test::Person::Employee:

     sub full_name : Tests(no_plan)
         my $test   = shift;
         $test->_full_name_validation;
         my $person = $test->class->new(
             first_name => 'Mary',
             last_name  => 'Jones',
         );
         is $person->full_name, 'Jones, Mary',
           'The employee name should render correctly';
     }

Just like with any other OO code, subclasses inherit and can override the _full_name_validation method.

Refactoring with fixtures

When writing test classes, the startup and shutdown methods are very handy, but those run only at the beginning and end of your test class. Sometimes you need code to run before the beginning and end of every test method. In the Person examples, many of the test methods contained this line:

     my $person = $test->class->new;

You really may not want to duplicate that every time, so you can use what's known as a fixture. A fixture is "fixed state" for your tests to run against. These allow you to remove duplicate setup code from your tests and to have a controlled environment. You might write:

     sub setup : Tests(setup) {
         my $test        = shift;
         my $class       = $test->class;
         $test->{person} = $class->new;
     }

If you want to start with a known set of data, you could write:

     sub setup : Tests(setup) {
         my $test        = shift;
         my $class       = $test->class;

         $test->{person} = $class->new(
             first_name => 'John',
             last_name  => 'Public',
         );
     }

Now all of your test methods can simply use $test->{person} (you can even make that a method if you prefer) to access a new instance of the class you're testing without having to duplicate that code.

The corresponding teardown method is useful if you need to clean up on a per test basis. This can be useful if you run tests against a database.

Next time, I'll discuss how to manage test classes with Test::Class.

Organizing Test Suites with Test::Class

When working with large test suites, using procedural tests for object-oriented code becomes clumsy after a while. This is where Test::Class really shines. Unfortunately, many programmers struggle to learn this module or don't use its full power.

Please note that article assumes a basic familiarity with object-oriented Perl and testing. Also, some of these classes are not "proper" by the standards of many OO programmers (your author included), but have been written for clarity rather than purity.

Modules and Their Versions

This article uses the following modules and versions:

  • Test::Class version 0.31
  • Test::Most version 0.21
  • Test::Harness version 3.15
  • Moose version 0.7
  • Class::Data::Inheritable version 0.08
  • You may use lower versions of these modules (and write the OO by hand instead of using Moose), but be aware that you may see slightly different behavior.

    Notes about the code

    Note that Moose packages should generally end with:

      __PACKAGE__->meta->make_immutable;
      no Moose;

    I've omitted this from the examples. I've also omitted use strict and use warnings, but assume they are there (they're automatically used when you use Moose). The code will, however, run just fine without this. I did this merely to focus on the core features of the code in question.

    Of course, you may need to adjust the shebang line (#!/usr/bin/env perl -T) for your system.

    Evolution of a Perl Programmer

    There are many paths programmers take in their development, but a typical one seems to be:

    1. Start writing simple procedural programs.
    2. Start writing modules to reuse code.
    3. Start using objects for more powerful abstractions.
    4. Start writing tests.

While it would be nice if people started writing tests from day 1, most programmers don't. When they do, they're often straight-forward procedural tests like:

     #!/usr/bin/env perl -T

     use strict;
     use warnings;

     use Test::More tests => 3;

     use_ok 'List::Util', 'sum' or die;

     ok defined &sum, 'sum() should be exported to our namespace';
     is sum(1,2,3), 6, '... and it should sum lists correctly';

There's nothing wrong with procedural tests. They're great for non-OO code. For most projects, they handle everything you need to do. If you download most modules off the CPAN you'll generally find their tests -- if they have them -- procedural in style. However, when you start to work with larger code bases, a t/ directory with 317 test scripts starts to get tedious. Where is the test you need? Trying to memorize all of your test names and grepping through your tests to find out which ones test the code you're working with becomes tedious. That's where Adrian Howard's Test::Class can help.

Using Test::Class

Creating a simple test class

I'm a huge "dive right in" fan, so I'll now skip a lot of the theory and show how things work. Though I often use test-driven development (TDD), I'll reverse the process here to show explicitly what I'm testing. Also, Test::Class has quite a number of different features, not all of which I'm going to explain here. See the documentation for more information.

First, create a very simple Person class. Because I don't like writing out simple methods over and over, I used Moose to automate a lot of the grunt work.

     package Person;

     use Moose;

     has first_name => ( is => 'rw', isa => 'Str' );
     has last_name  => ( is => 'rw', isa => 'Str' );

     sub full_name {
         my $self = shift;
         return $self->first_name . ' ' . $self->last_name;
     }

     1;

This provides a constructor and first_name, last_name, and full_name methods.

Now write a simple Test::Class program for it. The first bit of work is to find a place to put the tests. To avoid namespace collisions, choose your package name carefully. I like prepending my test classes with Test:: to ensure that we have no ambiguity. In this case, I've put my Test::Class tests in t/tests/ and named this first class Test::Person. Assume the directory structure:

     lib/
     lib/Person.pm
     t/
     t/tests/
     t/tests/Test
     t/tests/Test/Person.pm

The actual test class might start out like:

     package Test::Person;

     use Test::Most;
     use base 'Test::Class';

     sub class { 'Person' }

     sub startup : Tests(startup => 1) {
         my $test = shift;
         use_ok $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;

Note: this code uses Test::Most instead of Test::More to take advantage of Test::Most features later. Also, those methods should really be ro (read-only) because the code makes it possible to leave the object in an inconsistent state. This is part of what I meant about "proper" OO code, but again, I wrote this code for illustration purposes only.

Before I explain all of that, run this test. Add this program as t/run.t:

     #!/usr/bin/env perl -T

     use lib 't/tests';
     use Test::Person;

     Test::Class->runtests;

This little program sets the path to the test classes, loads them, and runs the tests. Now you can run that with the prove utility:

     $ prove -lv --merge t/run.t

Tip: The --merge tells prove to merge STDOUT and STDERR. This avoids synchronization problems that happen when STDERR is not always output in synchronization with STDOUT. Don't use this unless you're running your tests in verbose mode; it sends failure diagnostics to STDOUT. TAP::Harness discards STDOUT lines beginning with # unless running in verbose mode.

You will see output similar to:

     t/run.t ..
     1..4
     ok 1 - use Person;
     #
     # Test::Person->constructor
     ok 2 - Person->can('new')
     ok 3 - ... and the constructor should succeed
     ok 4 - ... and the object it returns isa Person
     ok
     All tests successful.
     Files=1, Tests=4,  0 wallclock secs ( 0.03 usr  0.00 sys +  0.43 cusr  0.02 csys =  0.48 CPU)
     Result: PASS

Note that the test output (named the "Test Anything Protocol", or "TAP", if you're curious) for the constructor method begins with the diagnostic line:

     # Test::Person->constructor

That occurs before every test method's output and makes it very easy to find which tests failed.

Look more closely at the test file to see what's happening:

     01: package Test::Person;
     02:
     03: use Test::Most;
     04: use base 'Test::Class';
     05:
     06: sub class { 'Person' }
     07:
     08: sub startup : Tests(startup => 1) {
     09:     my $test = shift;
     10:     use_ok $test->class;
     11: }
     12:
     13: sub constructor : Tests(3) {
     14:     my $test  = shift;
     15:     my $class = $test->class;
     16:     can_ok $class, 'new';
     17:     ok my $person = $class->new,
     18:         '... and the constructor should succeed';
     19:     isa_ok $person, $class, '... and the object it returns';
     20: }
     21:
     22: 1;

Lines 1 through 4 are straightforward. Line 4 makes this class inherit from Test::Class; and that's what makes all of this work. Line 6 defines a class method which the tests will use to know which class they're testing. It's very important to do this rather than hard-coding the class name in our test methods. That's good OO practice in general; it will help you later.

The startup method has an attribute, Tests with has the arguments startup and 1. Any method labeled as a startup method will run once before any of the other methods run. The 1 (one) in the attribute says "this method runs one test". If you don't run any tests in your startup method, omit this number:

     sub load_db : Tests(startup) {
         my $test = shift;
         $test->_create_database;
     }

     sub _create_database {
         ...
     }

Tip: as you can see from the code above, you don't need to name the startup method startup. I recommend you give it the same name as the attribute for reasons discussed later.

That will run once and only once for each test class. Because the _create_database method has no have any attributes, you may safely call it and Test::Class will not try to run it as a test.

Of course, there's a corresponding shutdown available:

     sub shutdown_db : Tests(shutdown) {
         my $test = shift;
         $test->_shutdown_database;
     }

These two attributes allow you to set up and tear down a pristine testing environment for every test class without worrying that other test classes will interfere with the current tests. Of course, this means that tests may not be able to run in parallel. Though there are ways around that, they're beyond the scope of this article.

As mentioned, the startup method has a second argument which tells Test::Class that it runs one test. This is strictly optional. Here we use it to safely test that we can load our Person class. As an added feature, if Test::Class detects that the startup test failed (or if it catches an exception), it assumes that there's no point in running the rest of the tests, so it skips the remaining tests for the class.

Tip: Don't run tests in your startup method; I'm doing so only to simplify this example. I'll explain why in a bit. For now, it's better to write:

     sub startup : Tests(startup) {
         my $test  = shift;
         my $class = $test->class;
         eval "use $class";
         die $@ if $@;
     }

Take a closer look at the constructor method.

     13: sub constructor : Tests(3) {
     14:     my $test  = shift;
     15:     my $class = $test->class;
     16:     can_ok $class, 'new';
     17:     ok my $person = $class->new,
     18:         '... and the constructor should succeed';
     19:     isa_ok $person, $class, '... and the object it returns';
     20: }

Tip: I did not name the constructor tests new because that's a Test::Class method and overriding it will cause the tests to break.

The Tests attribute lists the number of tests as 3. If you don't know how many tests you're going to have, use no_plan.

     sub constructor : Tests(no_plan) { ... }

As a short-cut, omitting arguments to the attribute will also mean no_plan:

     sub constructor : Tests { ... }

The my $test = shift line is equivalent to my $self = shift. I've like to rename $self to $test in my test classes, but that's merely a matter of personal preference. The $test object is an empty hashref. This allows you to stash data there, if needed. For example:

     sub startup : Tests(startup) {
         my $test     = shift;
         my $pid      = $test->_start_process
             or die "Could not start process: $?";

         $test->{pid} = $pid;
     }

     sub run : Tests(no_plan) {
         my $test    = shift;
         my $process = $test->_get_process($test->{pid});
         ...
     }

The rest of the test method is self-explanatory if you're familiar with Test::More.

The test class also had first_name, last_name, and full_name, so write those tests. When you're in "development mode", it's safe to leave these tests as no_plan, but don't forget to set the number of tests when you're done.

     sub first_name : Tests {
         my $test   = shift;
         my $person = $test->class->new;

         can_ok $person, 'first_name';
         ok !defined $person->first_name,
           '... and first_name should start out undefined';

         $person->first_name('John');
         is $person->first_name, 'John',
           '... and setting its value should succeed';
     }

     sub last_name : Tests {
         my $test   = shift;
         my $person = $test->class->new;

         can_ok $person, 'last_name';
         ok !defined $person->last_name,
           '... and last_name should start out undefined';

         $person->last_name('Public');
         is $person->last_name, 'Public',
           '... and setting its value should succeed';
     }

     sub full_name : Tests {
         my $test   = shift;
         my $person = $test->class->new;

         can_ok $person, 'full_name';
         ok !defined $person->full_name,
           '... and full_name should start out undefined';

         $person->first_name('John');
         $person->last_name('Public');

         is $person->full_name, 'John Public',
           '... and setting its value should succeed';
     }

Tip: when possible, name your test methods after the method they're testing. This makes finding them much easier. You can even write editor tools to automatically jump to them. Not all test methods will fit this pattern, but many will.

The first_name and last_name tests can probably have common elements factored out, but for now they're fine. Now see what happens when you run this (warnings omitted):

     t/run.t ..
     ok 1 - use Person;
     #
     # Test::Person->constructor
     ok 2 - Person->can('new')
     ok 3 - ... and the constructor should succeed
     ok 4 - ... and the object it returns isa Person
     #
     # Test::Person->first_name
     ok 5 - Person->can('first_name')
     ok 6 - ... and first_name should start out undefined
     ok 7 - ... and setting its value should succeed
     #
     # Test::Person->full_name
     ok 8 - Person->can('full_name')
     not ok 9 - ... and full_name should start out undefined

     #   Failed test '... and full_name should start out undefined'
     #   at t/tests/Test/Person.pm line 48.
     #   (in Test::Person->full_name)
     ok 10 - ... and setting its value should succeed
     #
     # Test::Person->last_name
     ok 11 - Person->can('last_name')
     ok 12 - ... and last_name should start out undefined
     ok 13 - ... and setting its value should succeed
     1..13
     # Looks like you failed 1 test of 13.
     Dubious, test returned 1 (wstat 256, 0x100)
     Failed 1/13 subtests

     Test Summary Report
     -------------------
     t/run.t (Wstat: 256 Tests: 13 Failed: 1)
       Failed test:  9
       Non-zero exit status: 1
     Files=1, Tests=13,  0 wallclock secs ( 0.03 usr  0.00 sys +  0.42 cusr  0.02 csys =  0.47 CPU)
     Result: FAIL

Uh oh. You can see that full_name isn't behaving the way the tests expect. Suppose that you want to croak if either the first or last name is not set. To keep this simple, assume that neither first_name nor last_name may be set to a false value.

     sub full_name {
         my $self = shift;

         unless ( $self->first_name && $self->last_name ) {
             Carp::croak("Both first and last names must be set");
         }

         return $self->first_name . ' ' . $self->last_name;
     }

That should be pretty clear. Look at the new test now. Use the throws_ok test from Test::Exception to test the Carp::croak(). Using Test::Most instead of Test::More makes this test function available without explicitly using Test::Exception.

 sub full_name : Tests(no_plan) {
     my $test   = shift;
     my $person = $test->class->new;
     can_ok $person, 'full_name';

     throws_ok { $person->full_name }
         qr/^Both first and last names must be set/,
         '... and full_name() should croak() if the either name is not set';

     $person->first_name('John');

     throws_ok { $person->full_name }
         qr/^Both first and last names must be set/,
         '... and full_name() should croak() if the either name is not set';

     $person->last_name('Public');
     is $person->full_name, 'John Public',
       '... and setting its value should succeed';
 }

Now all of the tests pass and you can go back and set the test plan numbers, if desired:

 All tests successful.
 Files=1, Tests=14,  0 wallclock secs ( 0.03 usr  0.00 sys +  0.47 cusr  0.02 csys =  0.52 CPU)
 Result: PASS

The next article, Reusing Test Code with Test::Class shows how to inherit from test classes -- and how to refactor test classes!

1