Chapter 14. Essential Testing

As briefly described in Chapter 13, a distribution contains a testing facility invoked from make test. This testing facility permits a module author to write and run tests during development and maintenance and the ultimate module installer to verify that the module works in the new environment.

Why have tests during development? One emerging school of thought states that the tests should be written first, even before the module is created, as a reflection of the module's specification. Of course, the initial test run against the unwritten module will show nearly complete failure. However, as functionality is added, proper functionality is verified immediately. (It's also handy to invoke the tests frequently as you code to make sure you're getting closer to the goal, not breaking more things.)

Certainly, errors may be found in the test suite. However, the defect rate for tests are usually far lower than the defect rate for complex module code; if a test fails, it's usually a good indication that there's more work to be done.

But even when Version 1.0 of the module is finally shipped, there's no need to abandon the test suite. Unless You code the mythical "bug-free module," there will be bug reports. Each bug report can (and should) be turned into a test.[1] While fixing the bug, the remaining tests prevent regression to a less functional version of the codehence the name regression testing.

[1] If you're reporting a bug in someone else's code, you can generally assume that sending them a test for the bug will be appreciated. A patch would be appreciated even more!

Then there's always the 1.1 or 2.0 releases to think about. When you want to add functionality, start by adding tests.[2] Because the existing tests ensure your upward compatibility, you can be confident that your new release does everything the old release did, and then some.

[2] And writing the documentation at the same time, made easier by Test::Inline, as you'll see later.

Good tests also give small examples of what you meant in your documentation, in case your writing isn't clear.[3] Good tests also give confidence to the installer that this code is portable enough to work on both your system and his system, including all stated and unstated dependencies.

[3] Many modules we've used from the CPAN were documented more by test examples than by the actual POD. Of course, any really good example should be repeated in your module's POD documentation.

Testing is an art. Dozens of how-to-test books have been written and read, and often ignored. Mostly, it's important to remember everything you have ever done wrong while programming (or heard other people do), and then test that you didn't do it again for this project.

Test things that should break (throw exceptions or return false values) as well as things that should work. Test the edges. Test the middle. Test one more or one less than the edge. Test things one at a time. Test many things at once. If something should throw an exception, make sure it didn't also negatively affect the state of the world before it threw the exception. Pass extra parameters. Pass insufficient parameters. Mess up the capitalization on named parameters. Throw far too much data at it. Throw far too little. Test what happens for undef. And so on.

For example, suppose that you want to test Perl's sqrt function, which calculates square roots. It's obvious that you need to make sure it returns the right values when its parameter is 0, 1, 49, or 100. It's nearly as obvious to see that sqrt(0.25) should come out to be 0.5. You should also ensure that multiplying the value for sqrt(7) by itself gives something between 6.99999 and 7.00001.[4] You should make sure that sqrt(-1) yields a fatal error and that sqrt(-100) does too. See what happens when you request sqrt(&test_sub( )), and &test_sub returns a string of "10000". What does sqrt(undef) do? How about sqrt( ) or sqrt(1,1)? Maybe you want to give your function a googol: sqrt( '1' . '0' x 100 ). Because this function is documented to work on $_ by default, you should ensure that it does so. Even a simple function such as sqrt should get a couple of dozen tests; if your code does more complex tasks than sqrt does, expect it to need more tests, too. There are never too many tests.

[4] Remember, floating-point numbers aren't always exact; there's usually a little roundoff. Feel free to write your tests to require more precision than this test implies but don't require more precision than you can get on another machine!

If you write the code and not just the tests, think about how to get every line of your code exercised at least once for full code coverage. (Are you testing the else clause? Are you testing every elsif case?) If you aren't writing the code or aren't sure, use the code coverage facilities.[5]

[5] Basic code coverage tools such as Devel::Cover are found in the CPAN.

Check out other test suites. The Perl distribution itself comes with thousands of tests, designed to verify that Perl compiles correctly on your machine in every possible way. Michael Schwern earned the title of "Perl Test Master" for getting the Perl core completely tested, and, still constantly beats the drum for "test! test! test!" in the community.

In summary, please write tests. Let's see how this is done.