Lightning Strikes Four Times
by Shlomi Fish, Bob Free, Mike Friedman, brian d foy
|
Pages: 1, 2, 3, 4
Using Test::Count
by Shlomi Fish
A typical Test::More test script contains several checks. It is preferable to keep track of the number of checks that the script is running (using use Test::More tests => $NUM_CHECKS or the plan tests => $NUM_CHECKS), so that if some checks are not run (for whatever reason), the test script will still fail when being run by the harness.
If you add more checks to a test file, then you have to remember to update the plan. However, how do you keep track of how many tests should run? I've already encountered a case where a DBI related module had a different number of tests with an older version of DBI than with a more recent one.
Enter Test::Count. Test::Count originated from a Vim script I wrote to keep track of the number of tests by using meta-comments such as # TEST (for one test) or # TEST*3*5 (for 15 tests). However, there was a limit to what I could do with Vim's scripting language, as I wanted a richer syntax for specifying the tests as well as variables.
Thus, I wrote the Test::Count module and placed it on CPAN. Test::Count::Filter acts as a filter, counts the tests, and updates them. Here's an example, taken from a code I wrote for a Perl Quiz of the Week:
#!/usr/bin/perl -w
# This file implements various functions to remove
# all periods ("."'s) except the last from a string.
use strict;
use Test::More tests => 5;
use String::ShellQuote;
sub via_split
{
my $s = shift;
my @components = split(/\./, $s, -1);
if (@components == 1)
{
return $s;
}
my $last = pop(@components);
return join("", @components) . "." . $last;
}
# Other Functions snipped.
# TEST:$num_tests=9
# TEST:$num_funcs=8
# TEST*$num_tests*$num_funcs
foreach my $f (@funcs)
{
my $ref = eval ("\\&$f");
is($ref->("hello.world.txt"), "helloworld.txt", "$f - simple"); # 1
is($ref->("hello-there"), "hello-there", "$f - zero periods"); # 2
is($ref->("hello..too.pl"), "hellotoo.pl", "$f - double"); # 3
is($ref->("magna..carta"), "magna.carta", "$f - double at end"); # 4
is($ref->("the-more-the-merrier.jpg"),
"the-more-the-merrier.jpg", "$f - one period"); # 5
is($ref->("hello."), "hello.", "$f - one period at end"); # 6
is($ref->("perl.txt."), "perltxt.", "$f - period at end"); # 7
is($ref->(".yes"), ".yes", "$f - one period at start"); # 8
is($ref->(".yes.txt"), "yes.txt", "$f - period at start"); # 9
}
Filtering this script through Test::Count::Filter provides the correct number of tests. I then add this to my .vimrc:
function! Perl_Tests_Count()
%!perl -MTest::Count::Filter -e 'Test::Count::Filter->new({})->process()'
endfunction
autocmd BufNewFile,BufRead *.t map <F3> :call Perl_Tests_Count()<CR>
Now I can press F3 to update the number of checks.
Test::Count supports +,-,*, /, as well as parentheses, so it is expressive enough for most needs.
Acknowledgements
Thanks to mrMister from Freenode for going over earlier drafts of this article and correcting some problems.

