Perl Code Kata: Testing Imports
by chromaticDecember 16, 2004
Perl Taint Test Kata introduced the idea of Perl Test Kata, small exercises designed to improve your understanding of Perl and your ability to write test-driven code. This article is the second in the series.
Import Testing Kata
Perl 5 added the ideas of namespaces and modules, making code reusable and easier to maintain. To allow convenience, it also added an importing mechanism to put code from a module into the current namespace.
Behind the scenes, when you use a module, Perl loads it
from disk and, if successful, calls the special method
import(). By convention, this generally imports functions.
Much of the time, import() mundanely installs subroutines into
the current namespace. That's why so many modules use Exporter to provide a
default import().
However, it's also a general module-loading hook that can perform many
different types of manipulations. For example, Filter::Simple allows the
use of source filters to transform code that looks entirely unlike Perl into
valid code in the using module. Other modules change their behavior depending
on any arguments passed to import(). This includes Test::More and Test::Simple, which interpret
their arguments as information about how many tests to run.
use Test::More 'no_plan';
# or
use Test::More tests => 100;
This feature is both powerful and important. Because of its importance,
it needs good tests. Because of its power and flexibility, it may seem
difficult to test an import() well. Here are three sample
implementations for you to practice testing.
Basic Exporting
package Basic::Exports;
use strict;
use base 'Exporter';
use vars '@EXPORT';
@EXPORT = qw( foo bar );
sub foo { 'foo' }
sub bar { 'bar' }
1;
The tests should check that using Basic::Exports exports foo()
and bar() to the appropriate namespace and that they return the
appropriate values. Another test is that the code use Basic::Exports
(); exports neither function.
Optional Exports
package Optional::Exports;
use strict;
use base 'Exporter';
use vars '@EXPORT_OK';
@EXPORT_OK = qw( foo bar baz );
sub foo { 'foo' }
sub bar { 'bar' }
sub baz { 'baz' }
1;
The tests should check that Optional::Exports exports nothing by default and only those functions named, if there are any.
Load-time Behavior
A few modules have curious behavior. My Pod::ToDemo behaves differently
when invoked from the command line versus when used within a module. This
makes it substantially more difficult to test. Rather than make you
reinvent the tests there, here's a simpler custom import()
that does different things based on its invocation. If invoked from the
command line, it prints a message to standard output. If used from a
module, it exports the same foo() subroutine as before.
package Export::Weird;
use strict;
sub import
{
my ($package, undef, $line) = caller();
if ( $line == 0 )
{
print "Invoked from command-line\n";
}
else
{
no strict 'refs';
*{ $package . '::foo' } = sub { 'foo' };
}
}
1;
The only really tricky test here must exercise the behavior of the module when invoked from the command line. Assume that the documentation of the module suggests invoking it via:
$ perl -MExport::Weird -e 1
The next page explains some techniques for testing these examples. For
best results, spend between 30 and 45 minutes working through the kata on
your own before looking at the hints. For more information on how modules,
use, and require work, see perldoc
perlmod and perldoc perlfunc.
Pages: 1, 2 |

