Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

Testing modules and methods while waiting for Santa

by TVSET (Chaplain)
on Dec 18, 2003 at 21:17 UTC ( #315658=perlmeditation: print w/replies, xml ) Need Help??

Trying to impress Santa, who is coming shortly, I pushed myself into studying the Test::* suite (Test::Simple, Test::More, and Test::Harness). Surprisingly, it turned out to be much simpler and faster to adopt, then I had estimated.

After playing around with bits from the Test::Tutorial and few other small and simple things, I decided to go real. :) One of the problems that happen to my code very often is leftovers. When I need to change the way something works, I just copy it over, give it a different name, and play with it, until it really works. Pretty often, as I mentioned, I forget to remove the backup copy, so it stays there doing nothing, being called from nowhere.

Another problem, which occurs less often, but still does, is the robot-like code deletion. If the sub is called rarely, I tend to forget that I need it and once in a while I do delete it and commit to CVS. Of course, that is easy to get back, but it does waste time.

Here is what I decided to do in order to get read of this two problems and to practice the Test::* set of modules a bit more:

#!/usr/bin/perl -w use strict; use Test::More 'no_plan'; # Change these values together # For some reason I didn't manage to use variables here use lib '../lib'; use MyProject; our $project = 'MyProject'; our $lib_dir = '../lib'; # All methods of all modules should be listed here. This # list can actually be generated by another script, but it # will defeat the whole purpose of this meditation. :) my %methods = ( 'ModuleA' => [ 'method_foo', 'method_bar', 'blah', ], 'ModuleB' => [ 'do_things', 'enjoy', ], ); # Firstly, I want to see that I haven't delete any of # the useful staff. foreach my $module (sort keys %methods) { foreach my $method (sort @{$methods{$module}}) { # NOTE: I only check modules which belong to the # project. External stuff is not tested. my $project_module = $project . '::' . $module; can_ok($project_module, $method) or diag("PROBLEM: method $project_module->$method is missing" +); } } # Secondly, I want to see that my tests are realistic, i.e. # that nothing is missing from the %methods. This will # push me either to update the test or remove the leftover # from the code. check_module_tests($project); # It's been a long time since my last recursive function, # btw. :) sub check_module_tests { my $target = shift; my $path_to_target = $lib_dir . '/' . $project; if ($target eq $project) { $path_to_target = $path_to_target . '.pm'; } else { $path_to_target = $path_to_target . '/' . join('/', split('::' +,$target)) } # Read module open (MODULE, "<$path_to_target") or die "$!"; my @module_lines = <MODULE>; close(MODULE); # Look for subs my @subs = grep(/^sub\s+/, @module_lines); # Check that our test suite is complete with all subs foreach my $sub (sort @subs) { chomp($sub); $sub =~ s/^sub\s+(.*?)\{.*$/$1/; $sub =~ s/\s+//g; my $ok_flag = 0; foreach my $test_sub (@{$methods{$target}}) { if ($test_sub eq $sub) { $ok_flag++; } } is ($ok_flag, 1, "No. of occurances of $sub in test suite") or diag('PROBLEM: ' . $target . '->' . $sub . ' is not in tes +t suite'); } # Look for modules my @uses = grep(/^use\s+${project}/, @module_lines); # Recursively test each module foreach my $use (sort @uses) { chomp($use); $use =~ s/^use\s+${project}::(.*?);/$1/; if (defined($methods{$use})) { check_module_tests($use); } # Don't complain about subs of modules which are not # in %methods themselves - that's obvious. :) else { fail ("Is module $use in test suite?"); diag ("PROBLEM: $target uses $use, but $use is not in test + suite"); } } }

It turned out to help me a lot. Maybe someone else will benefit from this. Note though, that you will either have to code in the same style that I do ("use" and "sub" are at the beginning of the line, blah, blah, blah) or change the regular expressions that match the code.

P.S.: Merry coming Christmas! :)

Edited by BazB: added readmore tag.

Replies are listed 'Best First'.
Re: Testing modules and methods while waiting for Santa
by rkg (Hermit) on Dec 18, 2003 at 22:38 UTC
    Welcome to the world of testing. (Not that I've been here all that long, but welcome.)

    For the benefit of others reading your post, let me point out that effective test suites can be pretty basic. Typically, my tests are a line or two each -- less elaborate than the systematic checker you posted here. My test file may contain many of these cases, but each unit test is pretty basic. And as I find bugs, I fix the bug and cover myself by testing that case.

    The XP approach of very simple unit tests, written before the code itself, testing basic and edge cases, is a strong strategy. If comprehensive, any code that passes the suite by definition matches the spec. In short, the tests document the common and unusual behavior of every object and method.

    Surely whomever brings you gifts this time of year will be impressed by any use of testing at all, so that should bode well for you!


      Welcome to the world of testing.

      Oh, thanks. I am not along, it seems. :)

      The XP approach of very simple unit tests, written before the code itself, testing basic and edge cases, is a strong strategy.

      XP approach, for those who still haven't heard of it, is an "Extreme Programming" approach. Google for more info. :)

      P.S.: Mentioned for the benefit of those reading through the thread. :)

Re: Testing modules and methods while waiting for Santa
by tachyon (Chancellor) on Dec 19, 2003 at 01:03 UTC

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://315658]
Approved by gjb
Front-paged by bart
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (1)
As of 2017-06-27 23:38 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (617 votes). Check out past polls.