Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Monday November 03, 2008
12:28 PM

use_ok is not ok.

[ #37797 ]

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.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • 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?

    • 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 l

      • 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.

  • something like

    #!/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

    • 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...)

      --

      --rjray

  • 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

  • In Padre I have the following code:

    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 com

    --
    • 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 =>