You probably see a lot of tests with use_ok in them. In general, this should be avoided. It gets needlessly duplicated in plenty of test code. Instead, try something like this in your 00-load.t file:
#!/usr/bin/env perl use strict; use warnings; use File::Find; use File::Spec; use lib 'lib'; use Test::More; BEGIN { my $DIR => 'lib/'; sub to_module($) { my $file = shift; $file =~ s{\.pm$}{}; $file =~ s{\\}{/}g; # to make win32 happy $file =~ s/^$DIR//; return join '::' => grep _ => File::Spec->splitdir($file); } my @modules; find({ no_chdir => 1, wanted => sub { push @modules => map { to_module $_ } $File::Find::name if /\.pm$/; }, }, $DIR ); plan tests => scalar @modules; for my $module (@modules) { use_ok $module or BAIL_OUT("Could not use $module"); } }
That's not perfect and I'm sure there's a module somewhere which does this, but it's a good start. Basically, it asserts that you can use all of the modules you've defined. You could easily update it to have exceptions, but if you can't use one, you get a bail-out (this stops tons of annoying test failures from a simple typo). Then, you can remove all of those annoyingly duplicated use_ok lines in your tests and just use the damned modules you need.
I see the value of having a test script which reality-checks that everything compiles, especially if there are big gaps in a test suite.
But I don't see what's wrong with "use_ok()" for a module that you neede to "use" anyway. It's hardly any more syntax. What's the harm?
Re:what's really wrong with use_ok?
Ovid on 2008-11-03T17:57:15
First, here's the general 'correct' incantation:
BEGIN {
use_ok 'Some::Module' or die "Cannot use Some::Module";
}If the module is not used in a "BEGIN" block, compile-time behavior is ignored (e.g., exported functions may alter how your code parses).
If you don't have the 'or die' (or BAIL_OUT), things can get even worse. If the module fails to load, but most of it compiled, you can get partially compiled code loaded. Your 'use_ok' failure may scroll off the screen but failures show up much later in the test program run (this is a very subtle bug and one which once caused and fellow programmers hours of debugging grief).
Finally, where's the canonical spot for that use_ok statement? I often see test suites where I open up four of five different test modules, each of which has identical use_ok statements at the top. Testing something more than once doesn't make it more true. However, if you think you need to test 'use'ing a module more than once -- perhaps it won't load if another module loads -- the you probably have some bad coupling in your code and your "use Some::Module" statement in the test will catch the error anyway. It's annoying to have to write that entire BEGIN block every time I want to use a module. Just putting it into one "load" test means I don't have to worry about that any more.
Re:what's really wrong with use_ok? summary
markjugg on 2008-11-06T16:34:55
So I would say it summarizes like this:
If "use" a module it fails, the test grinds to a halt, which is nearly always a reasonable result.
With "use_ok", the test may
/continue/ causing unexpected results later on, because the module is not loaded, or worse, partially loaded. Thanks for your clarification, Ovid.
#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
my $tests;
BEGIN { $tests += 3 }
use_ok 'Clone::Closure';
can_ok 'Clone::Closure', 'clone';
ok !main->can('clone'), 'clone not exported by default';
BEGIN { $tests += 2 }
use_ok 'Clone::Closure', 'clone';
can_ok 'main', 'clone';
BEGIN { plan tests => $tests }
BAIL_OUT('module will not load')
if grep !$_, Test::More->builder->summary;
as t/00use.t and then just use the modules after that. I'm deliberately ignoring the fact the use_ok ought to called at BEGIN time, as I'm not actually using any of the module's functionality in this test program.
Re:I generally use...
rjray on 2008-11-03T20:03:25
This is similar to my approach, though I don't usually test for specific functions or methods. Once I've established that the modules can load, I leave it to individual suites to test specific modules.
(But then, I also arrange my suites so that no suite is dependent on a module that hasn't already been vetted by a previous suite. I'm just anal-retentive that way...)
Problem with this approach is that you don't know when errors are raised which module raised them; it might have been a dependency of the ones which you loaded. Here's one I wrote recently;
use Test::More qw(no_plan);
use FindBin qw($Bin);
use File::Find;
my @modules;
my %uses;
finddepth(sub {
m{^\w.*\.pm$} && do {
my $module = $File::Find::name;
$module =~ s{.*/lib.}{};
$module =~ s{[/\\]}{::}g;
$module =~ s{.pm$}{};
push @modules, $module;
open MODULE, "<", $_ or die "Failed to open ($_): $!";
while(<MODULE>) {
if (m{^use (\S+)}) {
$uses{$module}{$1}++;
}
if (m{^(?:extends|with) (["'])?(\S+)\1}) {
$uses{$module}{$2}++;
}
}
close MODULE;
};
}, "$Bin/../lib");
my %done;
while (@modules) {
my (@winners) = grep {!$uses{$_} or !keys %{$uses{$_}}} @modules;
if (!@winners) {
@winners = shift @modules;
}
for my $module (sort @winners) {
my @fail;
local($SIG{__WARN__}) = sub {
push @fail, join " ", @_;
warn "# oh look a warning: @_";
};
use_ok($module);
is (@fail, 0, "no warnings issued");
$done{$module}++;
delete $uses{$module};
delete $_->{$module} for values %uses;
}
@modules = grep { !$done{$_} } @modules;
}
use strict;
use warnings;
use Test::More;
plan skip_all => 'Needs Test::Compile 0.08' if not eval "use Test::Compile 0.08; 1";
diag "Test::Compile $Test::Compile::VERSION";
all_pl_files_ok(all_pm_files());
The funny call at the end is because currently Test::Compile has all_pm_files_ok() that "use"-es all the pm files while all_pl_files_ok() runs "perl -cw path/to/module" on all modules.
The above combination provides the strongest way to check if every module can be compiled on its own.
Maybe what I'd really need though is to run
perl -cw -Mblib -MModule::Name -e1
one every module.
there's also Test::UseAllModules
ishigaki on 2008-11-09T03:50:00
I've been using Test::UseAllModules (since 2006) which reads MANIFEST and tries to load every
.pm module under "lib" directory, and if anything should fail, the test would bail out. A sample code is like this:
use strict;
use warnings;
use Test::UseAllModules;BEGIN {
all_uses_ok();
}The point is you don't need to find modules as it should be done by ExtUtils::Manifest when you ship the package.
There's a bug here that I didn't spot until I tried to run it:
my $DIR => 'lib/';
I think you mean "=" there, not =>
Re:bug: my $DIR = 'lib/';
Ovid on 2009-04-01T19:57:13
Agreed. Thanks for spotting that!