Listen Print Discuss

Perl Code Kata: Testing Imports

by chromatic
December 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

Next Pagearrow





Contact Us | Advertise with Us | Privacy Policy | Press Center | Jobs | Submissions Guidelines

Copyright © 2000-2008 O’Reilly Media, Inc. All Rights Reserved. | (707) 827-7000 / (800) 998-9938
All trademarks and registered trademarks appearing on the O'Reilly Network are the property of their respective owners.

For problems or assistance with this site, email