Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Design

Perl Testing


"A crash is when your competitor's program dies. When your program dies, it is an 'idiosyncrasy.' Frequently, crashes are followed with a message like 'ID 02.' 'ID' is an abbreviation for idiosyncrasy and the number that follows indicates how many more months of testing the product should have had." — Guy Kawasaki

Testing is the cornerstone of robust software development, and Perl supports a flexible and powerful testing capability. In this article, I examine the testing mechanisms available to Perl programmers, focusing on the Extreme Programming (XP) Test First principle. Test First turns the traditional waterfall methodology on its head by saying that test writing precedes not only coding but even design, and that tests come straight out of requirements. In fact, the tests are a formal expression of the requirements.

This approach makes enormous sense. A requirement is not a real requirement unless it is testable. "The product shall be user friendly" is not testable, while "the system shall process 100 record updates within 500ms" is. So why interpose a huge hiatus of design and implementation between writing the requirements and finding out whether they're testable? Moreover, a full-fledged regression and unit test suite provides the safety net that lets you perform feats of derring-do on the high wire of development, safe in the knowledge that at every step you can instantly check whether the code passes the tests no matter what massive changes you may have just wrought upon it.

Clearly, the developers of Perl have embraced the XP testing philosophy. Between 1997 and 2004, the number of tests for the core Perl distribution itself mushroomed from 5000 to 70,000.

Simple to Get Started

Being lazy means never having to say you've got carpal tunnel syndrome. The test module designers applied the principle of Huffman coding to the API; that is, the most common functions you call should have the shortest names to optimize typing and reading. The most common test function is simply called ok(), which is vastly more appealing than, say, TestSocketListenerConnectionFailure(). If you're impatient (another fundamental Perl virtue), you can write a test just by creating a program containing. For instance:


use Test::Simple tests => 1;
ok(sqrt(16) == 4, "sqrt(16) works");

As this shows, the ok() function is exported by the Test::Simple module that comes with Perl (since Perl 5.8.0, and before that in CPAN) and so is close to hand.

All that the ok() function does is test its first argument and print out "ok" or "not ok", depending on whether it is true. You're probably thinking, "I hardly need anyone to write a module to do that." But from such little test acorns do mighty regression suite oaks sprout. The ok() function also outputs the test label in the second argument and a running count of tests it has run. This is where the tests argument to Test::Simple comes in--it specifies how many tests we intend to run, so that Test::Simple can warn you if it sees a different number of calls to ok(). The output of a typical test program run looks like Listing One.

Listing One

1..12
ok 1 - regex search
ok 2 - regex search
ok 3 - regex search
ok 4 - regex store lives
ok 5 - regex store
ok 6 - Store non-matching regex croaks
ok 7 - Keys on complex store
ok 8 - Hash on complex store
ok 9 - lol regex store lives
ok 10 - lol regex store
ok 11 - Chained assignment
ok 12 - Multiple match croaks


The first line shows the range of tests expected to be run; the significance of this will be seen later. Any error output from the program is passed through.

All this serves to show that the testing of Perl programs fits the same philosophy as programming Perl: Simple tasks should be simple to achieve. In practice, most testing uses the Test::More module, which exports a number of more useful functions, including:

  • is($expr, $value, $tag) same as ok($expr eq $value, $tag).
  • like($expr, $regex, $tag, same as ok($expr =~ $regex, $tag).
  • is_deeply($struct1, $struct2, $tag), compares arbitrarily deep structures.
  • isa_ok($object, $class), verifies that an object is a member of a given class.
  • use_ok($module, @imports), test that a module can be loaded

Note again the Huffman principle on names of commonly used functions. Even though several of the functions are syntactic sugar for variations on ok() (and all of them end up calling ok() anyway), any improvement in readability justifies a new function so that testing can be made as painless as possible. (There's even an isnt() function to avoid having to put a negation operator in an is() call, and, in true Perl tradition, there's an isn't() alias.)

Test::More lets you designate blocks of tests as conditional in two different ways. By naming a block SKIP, you can then call the skip() function inside the block if you want to skip the tests in it:


SKIP: {
  eval { require Acme::Garden;
         Acme::Garden->export;
       };
  $@ and skip "Don't have Acme::Garden installed", 2;
  is(pull_weed(), "kudzu", "It's taking over!");
  is(seed_depth("gladiolus"), 7, "Flower module ok");
} 

The other way of marking tests as conditional is to put them in a block named "TODO". Failing tests in such a block will be specially annotated so as not to perturb aggregate statistics reported by Test::Harness.

The Perl test mechanism is not coupled to source code (Perl 5 does not lend itself easily to reflective tools; this will be remedied in Perl 6.) On the other hand, its simplicity allows it to be used to write unit tests, integration tests, regression tests, or acceptance tests.

Test::Simple is itself built on a module, Test::Builder, which is designed for reuse by modules providing testing functionality. The introduction of Test::Builder spurred an explosion in the creation of testing modules; there are currently over 250 such modules on CPAN in nearly 100 distributions. One of the more useful ones is Test::Exception, which verifies that code dies or fails to die when it should. You can also find Test::Pod, which vets the syntax of inline documentation written in POD ("Plain Old Documentation").


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.