Perl Best Practices [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Best Practices [Electronic resources] - نسخه متنی

Damian Conway

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


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.

/ 317