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.
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.