NAME

Test2::Tools::LoadModule - Test whether a module can be successfully loaded.

SYNOPSIS

use Test2::V0;
use Test2::Tools::LoadModule;

load_module_ok 'My::Module';

done_testing();

DESCRIPTION

This Test2::Tools module tests whether a module can be loaded, and optionally whether it has at least a given version, and exports specified symbols. It can also skip tests, or skip all tests, based on these criteria.

Test2::Manual::Testing::Migrating deals with migrating from Test::More to Test2::V0. It states that instead of require_ok() you should simply use the require() built-in, since a failure to load the required module or file will cause the test script to fail anyway. The same is said for use_ok().

In my perhaps-not-so-humble opinion this overlooks the fact that if you can not load the module you are testing, it may make sense to abort not just the individual test script but the entire test run. Put another way, the absence of an analogue to Test::More's require_ok() means there is no analogue to

require_ok( 'My::Module' ) or BAIL_OUT();

This module restores that functionality.

Note that if you are using this module with testing tools that are not based on Test2::V0 you may have to tweak the load order of modules. I ran into this in the early phases of implementation, and fixed it for my own use by initializing the testing system as late as possible, but I can not promise that all such problems have been eliminated.

CAVEAT

Accurately testing whether a module can be loaded is more complicated than it might first appear. One known issue is that you can get a false pass if the module under test forgets to load a module it needs, but this module loads it for its own use.

Ideally this module would use nothing that Test2 does not, but that seems to require a fair amount of wheel-reinventing. What this module does try to do is to load the extra modules only if it really needs them. Specifically:

Getopt::Long is loaded only if arguments are passed to the use Test::Tools::LoadModule statement.

File::Find and File::Spec are loaded only if all_modules_tried_ok() is called.

Because Carp and Exporter are used by Test2::API (at least as of version 1.302181), this module makes no attempt to avoid their use.

SUBROUTINES

All subroutines documented below are exportable, either by name or using one of the following tags:

:all exports all public exports;
:default exports the default exports (i.e. :test2);
:more exports require_ok() and use_ok();
:test2 exports load_module_*(), and is the default.

load_module_ok

load_module_ok $module, $ver, $import, $name, @diag;

Prototype: (@).

This subroutine tests whether the specified module (not file) can be loaded. All arguments are optional. The arguments are:

$module - the module name

This is the name of the module to be loaded. If unspecified or specified as undef, it defaults to the caller's CLASS if that exists; otherwise an exception is thrown.

$ver - the desired version number, or undef

If defined, the test fails if the installed module is not at least this version. An exception is thrown if the version number is invalid.

If undef, no version check is done.

$import - the import list as an array ref, or undef

This argument specifies the import list. undef means to import the default symbols, [] means not to import anything, and a non-empty array reference means to import the specified symbols.

$name - the test name, or undef

If undef, the name defaults to the code used to load the module. Note that this code, and therefore the default name, may change without notice.

@diag - the desired diagnostics

Diagnostics are only issued on failure.

Argument validation failures are signalled by croak().

The module is loaded, and version checks and imports are done if specified. The test passes if all these succeed, and fails otherwise.

Note that any imports from the loaded module take place when this subroutine is called, which is normally at run time. Imported subroutines will be callable, provided you do not make use of prototypes or attributes.

If you want anything imported from the loaded module to be available for subsequent compilation (e.g. variables, subroutine prototypes) you will need to put the call to this subroutine in a BEGIN { } block:

BEGIN { load_module_ok 'My::Module'; }

By default, $@ is appended to the diagnostics issued in the event of a load failure. If you want to omit this, or embed the value in your own text, see CONFIGURATION, below.

As a side effect, the names of all modules tried with this test are recorded, along with test results (pass/fail) for the use of all_modules_tried_ok().

load_module_or_skip

load_module_or_skip $module, $ver, $import, $name, $num;

Prototype: (@).

This subroutine performs the same loading actions as load_module_ok(), but no tests are performed. Instead, the specified number of tests is skipped if the load fails.

The arguments are the same as load_module_ok(), except that the fifth argument ($num in the example) is the number of tests to skip, defaulting to 1.

The $name argument gives the skip message, and defaults to "Unable to ..." where the ellipsis is the code used to load the module.

load_module_or_skip_all

load_module_or_skip_all $module, $ver, $import, $name;

Prototype: (@).

This subroutine performs the same loading actions as load_module_ok(), but no tests are performed. Instead, all tests are skipped if any part of the load fails.

The arguments are the same as load_module_ok(), except for the fact that diagnostics are not specified.

The $name argument gives the skip message, and defaults to "Unable to ..." where the ellipsis is the code used to load the module.

This subroutine can be called either at the top level or in a subtest, but either way it must be called before any actual tests in the file or subtest.

all_modules_tried_ok

all_modules_tried_ok

Added in version 0.002.

Prototype: (@).

This test traverses any directories specified as arguments looking for Perl modules (defined as files whose names end in .pm). A failing test is generated for any such file not previously tested using load_module_ok().

If no directory is specified, the default is ( '/blib/lib', '/blib/arch' ) .

NOTE that no attempt is made to parse the file and determine its module name. The module is assumed from the part of the file path below the specified directory. So an explicit specification of lib/ will work (if that is where the modules are stored) but an explicit blib/ will not.

clear_modules_tried

clear_modules_tried

Added in version 0.002.

Prototype: ().

This is not a test. It clears the record of modules tried by load_module_ok().

require_ok

require_ok $module;

Prototype: ($).

This subroutine is more or less the same as the Test::More subroutine of the same name. The argument is the name of the module to load.

use_ok

use_ok $module, @imports;
use_ok $module, $version, @imports;

Prototype: ($;@).

This subroutine is more or less the same as the Test::More subroutine of the same name. The arguments are the name of the module to load, and optional version (recognized by the equivalent of version::is_lax(), and optional imports.

CONFIGURATION

The action of the load_module_*() subroutines is configurable using POSIX-style options. If used as subroutine arguments they apply only to that subroutine call. If used as arguments to use(), they apply to everything in the scope of the use(), though this requires Perl 5.10 or above, and you must specify any desired imports.

These options are parsed by Getopt::Long (q.v.) in POSIX mode, so they must appear before non-option arguments. They are all documented double-dashed. A single leading dash is tolerated except in the form --option=argument, where the double dash is required.

The following configuration options are available.

--require

If asserted, this possibly-badly-named Boolean option specifies that an undef or unspecified import list imports nothing, while [] does the default import.

The default is -norequire, which is the other way around. This is the way use() works, which is what inspired the name of the option.

--req

This is just a shorter synonym for --require.

--load_error

--load_error 'Error: %s'

This option specifies the formatting of the load error for those subroutines that append it to the diagnostics. The value is interpreted as follows:

A string containing '%s'

or anything that looks like an sprintf() string substitution is interpreted verbatim as the sprintf format to use to format the error;

Any other true value (e.g. 1)

specifies the default, '%s';

Any false value (e.g. 0)

specifies that $@ should not be appended to the diagnostics at all.

For example, if you want your diagnostics to look like the Test::More require_ok() diagnostics, you can do something like this (at least under Perl 5.10 or above):

{	# Begin scope
  use Test2::Tools::LoadModule -load_error => 'Error:  %s';
  load_module_ok $my_module, undef, undef,
    "require $my_module;", "Tried to require '$my_module'.";
  ...
}
# -load_error reverts to whatever it was before.

If you want your code to work under Perl 5.8, you can equivalently do

load_module_ok -load_error => 'Error:  %s',
    $my_module, undef, undef, "require $my_module;"
    "Tried to require '$my_module'.";

Note that, while you can specify options on your initial load, if you do so you must specify your desired imports explicitly, as (e.g.)

use Test2::Tools::LoadModule
   -load_error => 'Bummer! %s', ':default';

SEE ALSO

Test::More

Test2::V0

Test2::Require

Test2::Manual::Testing::Migrating

Test2::Plugin::BailOnFail

SUPPORT

Support is by the author. Please file bug reports at https://rt.cpan.org/Public/Dist/Display.html?Name=Test2-Tools-LoadModule, https://github.com/trwyant/perl-Test2-Tools-LoadModule/issues, or in electronic mail to the author.

AUTHOR

Thomas R. Wyant, III wyant at cpan dot org

COPYRIGHT AND LICENSE

Copyright (C) 2019-2022 by Thomas R. Wyant, III

This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES.

This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.