In the previous screencast we created the is_any test function. This time we are going to move it to a separate module to be useful in other test scripts and to other test developers as well.
We can now reuse the is_any
function in this test script, but what if we would like to use it in several scripts?
What if we would like to allow other people in our organization to use it? And what if we want to share it via CPAN
so everyone using Perl will benefit from it?
In either case we need to create a module that provides this function. If we also want to share it publicly, we will need to create a distribution, but in any case first we need to create a module. We will use it like this:
use Test::More tests => 8;
use Test::Any qw(is_any);
And then in that test-script we can freely use the is_any
function.
As our first step, we create a standard-looking file called Test/Any.pm
and move the
is_any
function there:
package Test::Any;
use strict;
use warnings;
our $VERSION = '0.01';
use Exporter qw(import);
our @EXPORT_OK = qw(is_any);
use List::MoreUtils qw(any);
sub is_any {
my ($actual, $expected, $name) = @_;
$name ||= '';
local $Test::Builder::Level = $Test::Builder::Level + 1;
ok( (any {$_ eq $actual} @$expected), $name)
or diag "Received: $actual\nExpected:\n" .
join "", map {" $_\n"} @$expected;
}
1;
We declared the $VERSION
variable, just because it is good practice, and we also had to export the is_any
function.
For this we load the Exporter module and import the import
function from it.
(I know, it is a bit strange, I'll explain it in a separate article.)
Then, we also need to declare which functions are we ready to export. We do this by listing them in the @EXPORT_OK
variable
declared using our
.
That's it.
Except that we have a problem. In our code we call the is
function and the like
function and they are provided by
Test::More
. We should also load the Test::More
module, but that's not really proper. That module should be only loaded
by actual test scripts that will also set a plan.
Instead, what we need to do is reach to the engine behind Test::More
, and behind the plethora of Test::*
modules on CPAN that provides
this functionality. Namely, we need to use Test::Builder::Module.
After loading that module we can call my $Test = Test::Builder::Module->builder;
which will return the object that describes
the currently running test. As this module is a singleton, there is alwas going to be only one such object in every process.
This is the object that supplies the ok
method and the diag
method that are behind the respective functions of
Test::More
. Our code changes to the following:
package Test::Any;
use strict;
use warnings;
our $VERSION = '0.01';
use Exporter qw(import);
our @EXPORT_OK = qw(is_any);
use List::MoreUtils qw(any);
use Test::Builder::Module;
my $Test = Test::Builder::Module->builder;
sub is_any {
my ($actual, $expected, $name) = @_;
$name ||= '';
$Test->ok( (any {$_ eq $actual} @$expected), $name)
or $Test->diag("Received: $actual\nExpected:\n"
. join "", map {" $_\n"} @$expected);
}
1;
Please note, we don't need to adjust the Level
variable any more. That's because now our is_any
function is at the same level
as the ok/is/like/etc... functions exported by Test::More
. We created a function equivalent to the functions of Test::More
and of
Test::*
modules.
We just need to be able to distribute this and the user needs to be able to load it via a use
statement.