Документация
HTML CSS PHP PERL другое

Section 8.4.  Test::Builder

 
Previous
Table of Contents
Next

8.4. Test::Builder

But to be honest, who would want to write a test module from scratch anyway? Isn't there some module we could use to help us with that? Well, rather unsurprisingly, there is. Written by chromatic and maintained by Michael Schwern, the Test::Builder module provides you with useful functionality for, well, building a test module.

Test::Builder is an object-oriented module that implements the concept of a test object. This object performs some useful housekeeping work for us, such as keeping score of what test number we're at, how many tests have passed and failed, and so on, allowing us to concentrate on deciding whether or not a test should pass.

The test object also provides methods similar to the Test::More tests: ok, is, like, and so on. In fact, Test::Simple and Test::More are mostly just thin wrappers around Test::Builder methods.

Just like Apache->request, Test::Builder->new is a singleton object; future calls to new return the same object. This means you can use test routines from multiple different classes based on Test::Builder and they'll work together seamlessly maintaining a consistent count of passed and failed tests, along with the current test.

The usual incantation to begin using Test::Builder looks like this:

    use Test::Builder;
    my $Test = Test::Builder->new;

This creates a lexically scoped name for the singleton test object so you can refer to it directly within your test module. If you look into the code for Test::Simple, you'll find that's pretty much all there is to it: creating the Test::Builder object, an import subroutine, and an ok subroutine that simply calls the test object's ok method.

    sub ok ($;$) {
        $Test->ok(@_);
    }

The real magic is in the import routine. There are various different ways to set it up, depending on how important it is to be compatible with Perl 5.004 and earlier versions. One good example is in Test::Exception by Adrian Howard.

    sub import {
        my $self = shift;
        if (@_) {
            my $package = caller;
            $Test->exported_to($package);
            $Test->plan(@_);
        };
        $self->export_to_level(1, $self, $_) foreach @EXPORT;
    }

The critical bits of code here are the calls to the test object's exported_to and plan methods, which tell the test object where the test routines are exported to and set up the test plan. These two calls are wrapped in an if so that you can either use Test::Exception alone and have it set up its own test plan:

    use Test::Exception tests => 5;

or use it together with Test::More:

    use Test::More tests => 5;
    use Test::Exception;

Suppose you wanted to support fuzzy matching. We'll start with the standard steps to create a Test::Builder object and export our custom test routine. We'll use String::Approx to perform the fuzzy matching between the tested value and the expected value.

    package Test::Fuzzy;

    use Test::Builder;
    use String::Approx qw( amatch );

    use base qw( Exporter );
    our @EXPORT = qw( is_fuzzy );

    my $Test = Test::Builder->new;

Finally, we write is_fuzzy. Just like is, we'll take two strings as arguments and an optional test description:

    sub is_fuzzy ($$;$) {
        my ($got, $expected, $desc) = @_;
        my $result = amatch($expected, $got);
        $Test->ok($result, $desc);
    }

We don't even have to define an import subroutine if we leave Test::More to handle the test plan. To use our custom testing module, we use Test::More and Test::Fuzzy, then call our custom is_fuzzy test routine:

    use Test::More tests => 2;
    use Test::Fuzzy;

    is_fuzzy('one', 'none', "one is like none");
    is_fuzzy('blue', 'green', "blue is like green");

These two tests produce the following output:

    ok 1 - one is like none
    not ok 2 - blue is like green
    #     Failed test (fuzzy.t at line 7)

And that's it!

    Previous
    Table of Contents
    Next
    © 2000- NIV