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.

base class. Abstract the the name of the class you're testing into a class method in your base 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