The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

POE::Test::Helpers - Testing framework for POE

VERSION

version 1.07

SYNOPSIS

This module provides you with a framwork to easily write tests for your POE code.

The main purpose of this module is to be non-instrusive (or abstrusive) and allow you to write your code without getting in your way.

    package MySession;

    use Test::More tests => 1;
    use POE;
    use POE::Test::Helpers;

    # defining a callback to create a session
    my $run = sub {
        return POE::Session->create(
            inline_states => {
                '_start' => sub {
                    print "Start says hi!\n";
                    $_[KERNEL]->yield('next');
                },
                'next' => sub { print "Next says hi!\n" },
            }
        );
    };

    # here we define the tests
    # and tell POE::Test::Helpers to run your session
    POE::Test::Helpers->spawn(
        run   => $run,
        tests => {
            # _start is actually 0
            # next will run right after _start
            next => { order => 1 },
        },
    );

Testing event-based programs is not trivial at all. There's a lot of hidden race conditions and unknown behavior afoot. Usually we separate the testing to components, subroutines and events. However, as good as it is (and it's good!), it doesn't give us the exact behavior we'll get from the application once running.

There are also a lot of types of tests that we would want to run, such as:

  • Ordered Events:

    Did every event run in the specific order I wanted it to?

    (maybe some event was called first instead of third...)

  • Sequence Ordered Events:

    Did every event run only after other events?

    Imagine you want to check whether run_updates ran, but you know it can should only run after get_main_status ran. In event-based programming, you would give up the idea of testing this possible race condition, but with Test::POE::Helpers you can test it.

    run_updates can only run after get_main_status

  • Event Counting:

    How many times can each event run?

    (this event can be run only 4 times, no more, no less)

  • Ordered Event Parameters:

    Checking specific parameters an event received, supporting multiple options.

    (did this event get the right parameters for each call?)

  • Unordered Event Parameters:

    Same thing, just without having a specific order of sets of events.

This module allows to do all those things using a simple API.

METHODS

spawn

Creates a new POE::Session that manages in the background the tests. If you wish not to create a session, but manage things yourself, check new below and the additionally available methods.

Accepts the following options:

run

A callback to create your session. This is required so POE::Test::Helpers could hook up to your code internally without you having to set up hooks for it.

The callback is expected to return the session object. This means that you can either provide a code reference to your POE::Session->create() call or you could set up an arbitrary code reference that just returns a session object you want to monitor.

    use POE::Test::Helpers;

    # we want to test Our::Module
    POE::Test::Helpers->spawn(
        run => sub { Our::Module->spawn( ... ) },
        ...
    );

    # or, if we want to set up the session ourselves in more intricate ways
    my $object = Our::Module->new( ... );
    my $code   = sub { $object->create_session };

    POE::Test::Helpers->spawn(
        run => $code,
        ...
    );

In case you want to simply run a test in an asynchronous way (and that is why you're using POE), you could do it this way:

    use POE::Test::Helpers;

    sub start {
        # POE code
        $_[KERNEL]->yield('next');
    }

    sub next {
        # POE code
    }

    # now provide POE::Test::Helpers with a coderef that creates a POE::Session
    POE::Test::Helpers->spawn(
        run => sub {
            POE::Session->create(
                inline_states => [ qw/ _start next / ],
            );
        },
    );

tests

Describes what tests should be done. You need to provide each event that will be tested and what is tested on it and how. There are a lot of different tests that are available for you.

You can provide multiple tests per event, as much as you want.

    POE::Test::Helpers->spawn(
        run   => $run_method,
        tests => {
            # testing that "next" was run once
            next => { count => 1 },

            # testing that "more" wasn't run at all
            more => { count => 0 },

            # testing that "again" was run 3 times
            # and that "next" was run beforehand
            again => {
                count => 3,
                deps  => ['next'],
            },

            # testing that "last" was run 4th
            # and what were the subroutine parameters each time
            last => {
                order  => 3, # 0 is first, 1 is second...
                params => [ [ 'first', 'params' ], ['second'] ],
            },
        },
    );

params_type

Ordinarily, the params are checked in an ordered fashion. This means that it checks the first ones against the first arrayref, the second one against the third and so on.

However, sometimes you just want to provide a few sets of possible parameters which means it might be one of these, but necessarily in this order.

This helps in case of race conditions when you don't know what comes first and frankly don't even care.

You can change this simply by setting this attribute to unordered.

    use POE::Test::Helpers;

    POE::Test::Helpers->spawn(
        run          => $run_method,
        event_params => 'unordered',
        tests        => {
            checks => {
                # either called with "now" or "then" parameters
                # doesn't matter the order
                params => [ ['now'], ['then'] ],
            },
        },
    );

new

Creates an instance of the underlying object. Takes the exact same attributes as spawn above but does not create a POE::Session. This is useful if you want to embed the API and use it elsewhere.

This is what POE::Test::Helpers::MooseRole uses.

reached_event

A method of the underlying object that is injected into any event you want to test in the session returned by the run attribute.

To use it you must send it the information of the event you're in.

    $object->reached_event(
        name   => 'special',
        order  => 3, # we're 4th (counting starts at 0)
        params => [ @_[ ARG0 .. $# ] ], # if any
    );

check_deps

A method of the underlying object that runs a check of the event dependencies against the tests that were given.

check_order

A method of the underlying object that runs a check of the order of events against the tests that were given.

check_params

A method of the underlying object that runs a check of the parameters of events against the tests that were given.

check_all_counts

A method of the underlying object that requests to run count checks for every event.

check_count

A method of the underlying object that runs a check of the events' runtime count against the tests that were given.

AUTHOR

Sawyer, <xsawyerx at cpan.org>

BUGS

Please use the Github Issues tracker.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc POE::Test::Helpers

You can also look for information at:

ACKNOWLEDGEMENTS

I owe a lot of thanks to the following people:

  • Chris (perigrin) Prather

    Thanks for all the comments and ideas. Thanks for MooseX::POE!

  • Rocco (dngor) Caputo

    Thanks for the input and ideas. Thanks for POE!

  • #moose and #poe

    Really great people and constantly helping me with stuff, including one of the core principles in this module.

AUTHOR

  Sawyer X <xsawyerx@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by Sawyer X.

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