Section 18.2. Modular Testing


18.2. Modular Testing

Standardize your tests with Test::Simple or Test::More.

Writing tests always seems like a chore, and an unproductive chore at that: you don't have anything to test yet, so why write tests? And yet, most developers willalmost automaticallywrite driver software to test their new module in an ad hoc way:

     > cat try_inflections.pl      # Test my shiny new English inflections module...      use Lingua::EN::Inflect qw( inflect );     # Try some plurals (both standard and unusual inflections)...      my %plural_of = (         'house'         => 'houses',         'mouse'         => 'mice',         'box'           => 'boxes',         'ox'            => 'oxen',         'goose'         => 'geese',         'mongoose'      => 'mongooses',         'law'           => 'laws',         'mother-in-law' => 'mothers-in-law',     );     # For each of them, print both the expected result and the actual inflection...      for my $word ( keys %plural_of ) {         my $expected = $plural_of{$word};         my $computed = inflect( "PL_N($word)" );         print "For $word:\n",               "\tExpected: $expected\n",               "\tComputed: $computed\n";     }

A driver like that is actually harder to write than a test suite, because you have to worry about formatting the output in a way that is easy to read. And it's much harder to use the driver than it would be to use a test suite, because every time you run it you have to wade though that formatted output and verify "by eye" that everything is as it should be:

     > perl try_inflections.pl     For house:         Expected: houses         Computed: houses     For law:         Expected: laws         Computed: laws     For mongoose:         Expected: mongooses         Computed: mongeese     For goose:         Expected: geese         Computed: geese     For ox:         Expected: oxen         Computed: oxen     For mother-in-law:         Expected: mothers-in-law         Computed: mothers-in-laws     For mouse:         Expected: mice         Computed: mice     For box:         Expected: boxes         Computed: boxes

That's also error-prone; eyes are not optimized for picking out small differences in the middle of large amounts of nearly identical text.

Rather than hacking together a driver program, it's easier to write a test program using the standard Test::Simple module. Instead of print statements showing what's being tested, you just write calls to the ok( ) subroutine, specifying as its first argument the condition under which things are okay, and as its second argument a description of what you're actually testing:

          > cat inflections.t      use Lingua::EN::Inflect qw( inflect );     use Test::Simple qw( no_plan );     my %plural_of = (         'mouse'         => 'mice',         'house'         => 'houses',         'ox'            => 'oxen',         'box'           => 'boxes',         'goose'         => 'geese',         'mongoose'      => 'mongooses',         'law'           => 'laws',         'mother-in-law' => 'mothers-in-law',     );     for my $word ( keys %plural_of ) {         my $expected = $plural_of{$word};         my $computed = inflect( "PL_N($word)" );         ok( $computed eq $expected, "$word -> $expected" );     }

Test programs like this should be kept in files with a .t suffix (inflections.t, conjunctions.t, articles.t, ) and stored in a directory named t/ within your development directory for the application or module. If you set up your development directory using Module::Starter or Module::Starter::PBP (see "Creating Modules" in Chapter 17), this test directory will be set up for you automatically, with some standard .t files already provided.

Note that Test::Simple is loaded with the argument qw( no_plan ). Normally that argument would be tests => count, indicating how many tests are expected, but here the tests are generated from the %plural_of table at run time, so the final count will depend on how many entries are in that table. Specifying a fixed number of tests when loading the module is useful if you happen know that number at compile time, because then the module can also "meta-test": verify that you carried out all the tests you expected to.

The Test::Simple program is slightly more concise and readable than the original driver code, and the output is much more compact and informative:

          > perl inflections.t      ok 1 - house -> houses     ok 2 - law -> laws     not ok 3 - mongoose -> mongooses     #     Failed test (inflections.t at line 21)     ok 4 - goose -> geese     ok 5 - ox -> oxen     not ok 6 - mother-in-law -> mothers-in-law     #     Failed test (inflections.t at line 21)     ok 7 - mouse -> mice     ok 8 - box -> boxes     1..8     # Looks like you failed 2 tests of 8.

More importantly, this version requires far less effort to verify the correctness of each test. You just scan down the left margin looking for a "not" and a comment line.

You might prefer to use the Test::More module instead of Test::Simple. Then you can specify the actual and expected values separately, by using the is( ) subroutine, rather than ok( ):

      use Lingua::EN::Inflect qw( inflect );     use Test::More qw( no_plan );     
# Now using more advanced testing tools
my %plural_of = ( 'mouse' => 'mice', 'house' => 'houses', 'ox' => 'oxen', 'box' => 'boxes', 'goose' => 'geese', 'mongoose' => 'mongooses', 'law' => 'laws', 'mother-in-law' => 'mothers-in-law', ); for my $word ( keys %plural_of ) { my $expected = $plural_of{$word}; my $computed = inflect( "PL_N($word)" );
# Test expected and computed inflections for string equality...
is( $computed, $expected, "$word -> $expected" ); }

Apart from no longer having to type the eq yourself[*], this version also produces more detailed error messages:

[*] The ok subroutine is still available from Test::More if you do want to specify your own comparisons.

          > perl inflections.t      ok 1 - house -> houses     ok 2 - law -> laws     not ok 3 - mongoose -> mongooses     #     Failed test (inflections.t at line 20)     #          got: 'mongeese'     #     expected: 'mongooses'     ok 4 - goose -> geese     ok 5 - ox -> oxen     not ok 6 - mother-in-law -> mothers-in-law     #     Failed test (inflections.t at line 20)     #          got: 'mothers-in-laws'     #     expected: 'mothers-in-law'     ok 7 - mouse -> mice     ok 8 - box -> boxes     1..8     # Looks like you failed 2 tests of 8.

The Test::Tutorial documentation that comes with Perl 5.8 provides a gentle introduction to both Test::Simple and Test::More.



Perl Best Practices
Perl Best Practices
ISBN: 0596001738
EAN: 2147483647
Year: 2004
Pages: 350
Authors: Damian Conway

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net