Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Release history of Test-Functional

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 lib
Octocat-spinner-32 t
Octocat-spinner-32 Build.PL
Octocat-spinner-32 Changes
Octocat-spinner-32 MANIFEST
Octocat-spinner-32 META.yml
Octocat-spinner-32 Makefile.PL
Octocat-spinner-32 README
README
NAME
    Test::Functional - Perl tests in a functional style.

SYNOPSIS
      use Test::Functional;

      # make sure the bomb goes off
      sub explode { die "BOOM" }
      test { explode() } dies, "test-3";

      # implicit and explicit equivalence
      test { 2 * 2 } 4, "test-1";
      test { 2 * 2 } eqv 4, "test-1";

      # test blocks can be as simple or as involved as you want
      test { 3 > 0 } true, "test-4";
      test {
          my $total = 0;
          foreach my $person ($car->occupants) {
              $total += $person->weight
          }
          $total < 600
      } true, "test-5";

      # after the test runs, you also get the result.
      my $horse = test { Horse->new } typeqv "Horse", "test-6";

      # you can make your own comparator functions, or use existing ones.
      use Test::More import => [qw(like)];
      sub islike {
          my ($other) = @_;
          return sub {
              my ($got, $testname) = @_;
              like($got, $other, $testname);
          };
      }
      test { 'caterpillar' } islike(qr/cat/), 'is cat?';

DESCRIPTION
    This modules uses (abuses?) the ability to create new syntax via perl
    prototypes to create a testing system focused on functions rather than
    values. Tests run blocks of Perl, and use comparator functions to test
    the output. Despite being a different way of thinking about tests, it
    plays well with Test::More and friends.

EXPORTS
    Since this module is going to be used for test scripts, its methods all
    export by default. You can choose which you want using the standard
    directives:

        # import only eqv
        use Test::Functional tests => 23, import => ['eqv'];

        # import all but notest
        use Test::Functional tests => 23, import => ['!notest'];

CONFIGURE
    This package has two settings which can be altered to change
    performance:

        unstable - run tests which are normally skipped
        fastout  - cause the entire test to end after the first failure

    This package can be configured via Test::Functional::Conf or the
    configure() function.

    configure KEY => VALUE, ...
        Changes configuration values at run-time.

TEST STRUCTURES
    test { BLOCK } [CONDITION,] NAME
        This is the basic building block of Test::Functional. Each test
        function contains an anonymous code block (which is expected to
        return a scalar *result*), a name for the test, and a condition (an
        optional subroutine to check the result).

        In most cases, a test passes if the code block doesn't die, and if
        the condition is true (or absent). There is a special condition
        *dies* which expects the code block to die, and fails unless it does
        so.

        Whether the test passes or fails, *test* returns the value generated
        by *BLOCK*.

    pretest { BLOCK } [CONDITION,] NAME
        This works like *test* except that if it fails, it will
        short-circuit all testing at the current level. This means that
        top-level *pretest* calls will halt the entire test if they fail.
        One obvious example for this is:

            BEGIN { pretest { use Foo::Bar } "test-use" }
            test { Foo::Bar::double(2) } eqv(4), "double(2)";
            test { Foo::Bar::double(3) } eqv(6), "double(3)";
            test { Foo::Bar::double(4) } eqv(8), "double(4)";

        If the "use Foo::Bar" fails, the information that all the other
        tests are failing is less useful. *pretest* can also be combined
        with *group* (described later) to short-circuit a small set of
        related tests.

    notest { BLOCK } [CONDITION,] NAME
        This is has exactly the same semantics as *test*; the only
        difference is that it normally doesn't run. If
        "Test::Functional::Conf->unstable" is true, then this test will run,
        otherwise it won't, and will just return undef.

        For test-driven development, it is useful to create failing tests
        using *notest* blocks; this prevents test regression. Once the
        implementation starts working *notest* can be switched to *test*.

    group { BLOCK } NAME
        Groups are blocks which wrap associated tests. Groups can be used to
        namespace tests as well as to allow groups of tests to fail
        together. Here is a short example:

            group {
                my $a = coretest { Adder->new } typeqv 'Adder', "new";

                test { $a->add(4, 6) } 10, "4 + 6";
                test { $a->add("cat", "dog") } dies, "mass hysteria";
                test { $a->add() } isundef, "not a number";

            } "adder";

        If "Adder->new" fails, the rest of the tests aren't producing useful
        results, so they will be skipped. See the ETHOS section for a more
        in-depth discussion of the package in general, and the implications
        of test short-circuiting in particular.

TEST CONDITIONS
    eqv OBJECT
        Creates a function which tests that the result is exactly equivalent
        (eqv) to *OBJECT* (using Test::More::is_deeply). It works for both
        simple values and nested data structures. See Test::More for more
        details.

        If *test* receives a condition which isn't a code-ref, it will be
        wrapped in an *eqv* call, since this is the most common case
        (testing that a result is the expected value).

    ineqv OBJECT
        Tests whether the result differs from (is inequivalent to) *OBJECT*
        according to Data::Compare. This is expected (hoped?) to be inverse
        of *eqv*.

    typeqv TYPE
        Creates a function which tests that the result is of (or inhereits
        from) the provided *TYPE* (that the result's type is equivalent to
        *TYPE*). For unblessed references, it checks that "ref($result) eq
        $type". For blessed references it checks that "$result->isa($type)".
        Results which are not references will always be false.

    dies
        Verifies that the test's code block died. It is unique amongst test
        conditions in that it doesn't test the result, but rather tests $@.
        Any result other than a die succeeds.

    noop
        This is the "default" condition; if no condition is given to a test
        then this condition is used. As long as the code block does not die,
        the test passes.

    true
        Verifies that the result is a true value.

    false
        Verifies that the result is a false value.

    isdef
        Checks that the result is defined (not undef).

    isundef
        Checks that the result is undefined.

CUSTOM TEST CONDITIONS
    Anonymous subroutines can be used in place of the provided test
    conditions. These functions take two arguments: the test result and the
    test's name. Here are some examples:

      use Test::More;

      sub over21 {
          my ($result, $name) = @_;
          return cmp_ok($result, '>=', 21, $name);
      }
      test { $alice->age } \&over21, 'can alice drink?';
      test { $bob->age } \&over21, 'can bob drink?';

    These examples are kind of clunky, but you get the idea. Using anything
    complicated will probably require reading the source, and/or learning
    how to use Test::Builder. In particular, it's important to make sure
    "builder->level" is set correctly.

ETHOS
    This package exists to address some specific concerns I've had while
    writing tests using other frameworks. As such, it has some pretty major
    differences from the other testing frameworks out there.

    Most Perl tests are written as perl scripts which test Perl code by
    calling functions or methods, and then using various Test packages to
    look at the result. This approach has some problems:

    1   Test scripts can make bad assumptions or have bugs, causing problems
        that aren't obviously linked to a particular test clause and which
        can be hard to track down and fix.

    2   Writing defensive test scripts involves a bunch of relatively
        boiler-plate eval-blocks and $@ tests, as well as effectively
        doubling the number of tests that are "run" without meaningfully
        doubling the test coverage.

    3   In some cases a small early error causes tons of test clauses to
        spew useless messages about failing; this loses sight of the basic
        issue that caused the problem (syntax error, missing module, etc).

    Test::Functional addresses these concerns: it enables the programmer to
    write all the "meat" of the test script inside anonymous subs which are
    tests [1]. Since each test checks both that the code did not die and
    that the result was what was expected, the tester doesn't have to worry
    about what kind of failure might occur, just about the expected outcome
    [2]. Especially when trying to test other people's code (gray box
    testing?) this feature is invaluable.

    The various features to prematurely end the test (using *pretest()*
    and/or "$Test::Functional::Conf->fastout") can help the developer to
    focus on the problem at hand, rather than having to filter through spew
    [3]. This is especially nice during test-driven development, or when
    trying to increase coverage for an old and crufty module.

AUTHOR
    Erik Osheim "<erik at osheim.org>"

BUGS
    The syntax takes some getting used to.

    I should create default wrappers for things such as *like* and *compare*
    from Test::More. Currently I mostly use *true* but that gives less
    debugging information.

    I wrote these tests to suit my needs, so I am sure there are cases I
    haven't thought of or encountered. Also, I'm sure I have a lot to learn
    about the intricacies of Test::Harness and Test::Module. Please contact
    me (via email or <http://rt.cpan.org>) with any comments, advice, or
    problems.

ACKNOWLEDGEMENTS
    This module is based on Test::Builder::Module, and relies heavily on the
    work done by Michael Schwern. It also uses Data::Compare by David
    Cantrell.

COPYRIGHT & LICENSE
    Copyright 2009 Erik Osheim, all rights reserved.

    This program is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

Something went wrong with that request. Please try again.