/Test-Plan

CPAN distribution Test::Plan (released 12/2005)

Primary LanguagePerl

NAME

Test::Plan - add some intelligence to your test plan

SYNOPSIS

use Test::More;
use Test::Plan;

plan tests => 2, need_module('Foo::Bar');

# ... do something that requires Foo::Bar in your test environment...

ok($foo, 'this is Test::More::ok()');

DESCRIPTION

Test::Plan provides a convenient way of scheduling tests (or not) when the test environment has complex needs. it includes an alternate plan() function that is Test::Builder compliant, which means Test::Plan can be used alongside Test::More and other popular Test:: modules. it also includes a few helper functions specifically designed to be used with plan() to make test planning that much easier.

in reality, there is nothing you can't do with this module that cannot be accomplished via the traditional skip_all. however, the syntax and convenient helper functions may appeal to some folks. in fact, if you are familiar with Apache-Test then you should feel right at home - the plan() syntax and associated helper functions are idential in almost all respects to what Apache::Test provides.

so yes, there is lots of code duplication between this module and Apache::Test. but I like this syntax so much I wanted to share it with the non-Apache inspired world.

PLAN

the following functions are identical in almost all respects to those found in the Apache::Test package, so reading the Apache::Test manpage is highly encouraged.

  • plan()

    for all practical purposes, Test::Plan::plan() is a drop-in replacement for the other plan() functions you have been using already. in other words you can just

      use Test::Plan;
    
      plan tests => 3;
    

    and be on your way. where Test::Plan::plan() is different is that it takes an optional final argument that is used to decide whether the plan should occur or not. that is

      use Test::Plan;
    
      plan tests => 3, sub { $^O ne 'MSWin32' };
    

    has the same results as

      use Test::More;
    
      if ( $^O ne 'MSWin32' ) {
        plan tests => 3;
      }
      else {
        plan 'skip_all';
      }
    

    much better, eh? here is what you need to know...

    first, the final argument to plan() can be in any of the following formats. if the result evaluates to true the test is planned, otherwise the entire test is skipped a la skip_all.

    • a boolean

      the boolean option is typically the result from a subroutine that has already been evaluated. here is an example

        plan tests => 3, foo();
      

      at runtime, foo() will be evaluated and the results passed as the final argument to plan(). if the results are true then plan() will plan your tests, otherwise the entire test file is skipped.

      while you can write your own subroutines, as in the above example, you may be interested in using some of the helper functions Test::Plan provides.

    • a reference to a subroutine

      if the final argument to plan() is a reference to a subroutine that subroutine will be evaluated and the results used to decide whether to plan your tests.

        plan tests => 3, sub { 1 };
      

      or

        plan tests => 3, \&foo;
      

      if the subroutine evaluates to true then plan() will plan your tests, otherwise the entire test file is skipped.

    • a reference to an array

      this is a shortcut to calling need_module() for each element in the array. for example

        plan tests => 3, [ qw(CGI LWP::UserAgent) ];
      

      is exactly equivalent to

        plan tests => 3, need_module(qw(CGI LWP::UserAgent));
      

      see the below explanation of need_module() for more details.

    in general, Test::Plan::plan() functions identically to Apache::Test::plan(), so reading the Apache::Test manpage is highly encouraged.

HELPER FUNCTIONS

you might be wondering where the skip message comes from when you use Test::Plan::plan() as described above. the answer is that it comes from using one or more of the following helper functions.

  • need()

    need() is a special function that is best described via an illustration.

      plan tests => 3, need need_module('Foo::Bar'),
                            need_min_module_version(CGI => 3.0),
                            need_min_perl_version(5.6);
    

    what happens here is that need() is dispatching to each decision-making function and aggregating the results. the result is that the skip message contains all the conditions that failed, not merely the first one. contrast the above to this

      plan tests => 3, need_module('Foo::Bar')              &&
                       need_min_module_version(CGI => 3.0)  &&
                       need_min_perl_version(5.6);
    

    in this example if Foo::Bar is not present the list of preconditions is short-circuited and the others not even tried, which means that if you fix the Foo::Bar problem and run the test again you might be hit with other precondition failures. need() is a function of convenience, showing you all your failed preconditions at once.

    need() can accept arguments in the following forms:

    • another helper function

      this corresponds to the need() examples shown to this point. note that this is not the same as a boolean - need() looks specifically for 0 or 1 to be returned from its functions. for the reasons why see the next entry or read that Apache::Test manpage.

    • a scalar

      a simple scalar will be passed to need_module()

        plan tests => 3, need qw(Foo::Bar CGI);
      

      see the below entry for need_module() for the specifics.

    • a reference to a hash

      the key to the hash should be the skip message and the value the thing to be evaluated, either a boolean or a reference to a subroutine.

        plan tests => 3, need { 'not Win32' => sub { $^O eq 'MSWin32' },
                                'no Foo'    => need_module('Foo::Bar'),
                              };
      

      if the value evaluates to true then key is used as the skip message.

    this is all rather complex, so if you are confused please see the Apache::Test manpage. remember, I didn't write this stuff :)

  • need_module()

    determines whether a Perl module can be successfully required.

      plan tests => 3, need_module('Foo::Bar');
    

    will plan the tests only if Foo::Bar is present. the skip message will show that the module could not be found.

    need_module() accepts either a list or a reference to an array. in both cases all modules must be present for plan() to plan tests.

      plan tests => 3, need_module [ 'CGI', 'Foo::Bar', 'File::Spec' ];
    
  • need_min_module_version()

    this first calls need_module(). if that succeeds then the module version is checked using UNIVERSAL::VERSION. if the version is greater than or equal to the specified version tests are planned.

      plan tests => 3, need_min_module_version(CGI => 3.01);
    

    if no version is specified then a version check is not performed. this is a difference between Test::Plan and Apache::Test.

  • need_min_perl_version()

    similar to need_min_module_version(), checks to make sure that the version of perl currently running is greater than or equal to the version specified.

      plan tests => 3, need_min_perl_version(5.6);
    
  • need_perl()

    need_perl() queries Config for various properties. for example

      plan tests => 3, need_perl('ithreads');
    

    is equivalent to

      plan tests => 3, sub { $Config{useithreads} eq 'define' };
    

    in general, the argument to need_perl() is prepended with the string 'use' and the value within %Config checked. a special case is 'iolayers' which is dispatched to need_perl_iolayers().

  • need_threads()

    a shortcut to need_perl('ithreads').

  • need_perl_iolayers()

    returns true if perl contains PerlIO extensions.

  • skip_reason()

    this is a direct interface into the skip reason mechanism Test::Plan uses behind the scenes.

      plan tests => 3, skip_reason("I haven't implemented this feature yet");
    

    while it is useful for one liners, you can also use it from your own custom subroutine

      plan tests => 3, \&foo;
    
      sub foo {
        ...
        return 1 if $foo;  # success
        return skip_reason('condition foo not met');
      }
    
  • under_construction()

    skips the test with a generic 'under construction' skip message

      plan tests => 3, under_construction;
    

CAVEATS

this module jumps through some hoops so that you can use both Test::Plan and Test::More in the same script without a lot of trouble. the main issue is that both modules want to export plan() into your namespace, which results in warnings and collisions.

if you want to keep things simple, load Test::More before Test::Plan and everything should work out ok.

use Test::More;
use Test::Plan;

plan tests => 3, need_min_perl_version(5.6);

# nary a warning to be found.

otherwise you would need to be explicit in what you import from each module

use Test::Plan qw(plan need_module);
use Test::More import => [qw(!plan)];

plan tests => 3, need_module('Foo::Bar');

yucko.

FEATURES/BUGS

since the vast majority of the code here has been lifted from Apache::Test it is very well tested. the only novel thing is the Test::More workarounds mentioned in CAVEATS.

SEE ALSO

Apache::Test, Test::More

AUTHOR

Geoffrey Young geoff@modperlcookbook.org

COPYRIGHT

Copyright (c) 2005, Geoffrey Young All rights reserved.

This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.