NAME
    Test2::Roo - Composable, reusable tests with roles and Moo

VERSION
    version 1.005

SYNOPSIS
    Define test behaviors and required fixtures in a role:

        # t/lib/ObjectCreation.pm

        package ObjectCreation;
        use Test2::Roo::Role;    # loads Moo::Role and Test2::V0

        requires 'class';       # we need this fixture

        test 'object creation' => sub {
            my $self = shift;
            require_ok( $self->class );
            my $obj  = new_ok( $self->class );
        };

        1;

    Provide fixtures and run tests from the .t file:

        # t/test.t

        use Test2::Roo; # loads Moo and Test2::V0
        use lib 't/lib';

        # provide the fixture
        has class => (
            is      => 'ro',
            default => sub { "Digest::MD5" },
        );

        # specify behaviors to test
        with 'ObjectCreation';

        # give our subtests a pretty label
        sub _build_description { "Testing " . shift->class }

        # run the test with default fixture
        run_me;

        # run the test with different fixture
        run_me( { class => "Digest::SHA1" } );

        done_testing;

    Result:

        $ prove -lv t
        t/test.t ..
                ok 1 - require Digest::MD5;
                ok 2 - The object isa Digest::MD5
                1..2
            ok 1 - object creation
            1..1
        ok 1 - Testing Digest::MD5
                ok 1 - require Digest::SHA1;
                ok 2 - The object isa Digest::SHA1
                1..2
            ok 1 - object creation
            1..1
        ok 2 - Testing Digest::SHA1
        1..2
        ok
        All tests successful.
        Files=1, Tests=2,  0 wallclock secs ( 0.02 usr  0.01 sys +  0.06 cusr  0.00 csys =  0.09 CPU)
        Result: PASS

DESCRIPTION
    This module allows you to compose Test2::V0 tests from roles. It is
    inspired by the excellent Test::Routine module, but uses Moo instead of
    Moose. This gives most of the benefits without the need for Moose as a
    test dependency.

    Test files are Moo classes. You can define any needed test fixtures as
    Moo attributes. You define tests as method modifiers -- similar in
    concept to "subtest" in Test2::V0, but your test method will be passed
    the test object for access to fixture attributes. You may compose any
    Moo::Role into your test to define attributes, require particular
    methods, or define tests.

    This means that you can isolate test *behaviors* into roles which
    require certain test *fixtures* in order to run. Your main test file
    will provide the fixtures and compose the roles to run. This makes it
    easy to reuse test behaviors.

    For example, if you are creating tests for Awesome::Module, you could
    create the test behaviors as Awesome::Module::Test::Role and distribute
    it with your module. If another distribution subclasses Awesome::Module,
    it can compose the Awesome::Module::Test::Role behavior for its own
    tests.

    No more copying and pasting tests from a super class! Superclasses
    define and share their tests. Subclasses provide their own fixtures and
    run the tests.

USAGE
    Importing Test2::Roo also loads Moo (which gives you strictures with
    fatal warnings and other goodies) and makes the current package a
    subclass of Test2::Roo::Class.

    Importing also loads Test2::V0. No test plan is used. The "done_testing"
    function must be used at the end of every test file. Any import
    arguments are passed through to Test2::V0's "import" method.

    See also Test2::Roo::Role for test role usage.

  Creating fixtures
    You can create fixtures with normal Moo syntax. You can even make them
    lazy if you want:

        has fixture => (
            is => 'lazy'
        );

        sub _build_fixture { ... }

    This becomes really useful with Test2::Roo::Role. A role could define
    the attribute and require the builder method to be provided by the main
    test class.

  Composing test roles
    You can use roles to define units of test behavior and then compose them
    into your test class using the "with" function. Test roles may define
    attributes, declare tests, require certain methods and anything else you
    can regularly do with roles.

        use Test2::Roo;

        with 'MyTestRole1', 'MyTestRole2';

    See Test2::Roo::Role and the Test2::Roo::Cookbook for details and
    examples.

  Setup and teardown
    You can add method modifiers around the "setup" and "teardown" methods
    and these will be run before tests begin and after tests finish
    (respectively).

        before  setup     => sub { ... };

        after   teardown  => sub { ... };

    You can also add method modifiers around "each_test", which will be run
    before and after every individual test. You could use these to prepare
    or reset a fixture.

        has fixture => ( is => 'lazy, clearer => 1, predicate => 1 );

        after  each_test => sub { shift->clear_fixture };

    Roles may also modify "setup", "teardown", and "each_test", so the order
    that modifiers will be called will depend on when roles are composed. Be
    careful with "each_test", though, because the global effect may make
    composition more fragile.

    You can call test functions in modifiers. For example, you could confirm
    that something has been set up or cleaned up.

        before each_test => sub { ok( ! shift->has_fixture ) };

  Running tests
    The simplest way to use Test2::Roo with a single .t file is to let the
    "main" package be the test class and call "run_me" in it:

        # t/test.t
        use Test2::Roo; # loads Moo and Test2::V0

        has class => (
            is      => 'ro',
            default => sub { "Digest::MD5" },
        );

        test 'load class' => sub {
            my $self = shift;
            require_ok( $self->class );
        }

        run_me;
        done_testing;

    Calling "run_me(@args)" is equivalent to calling
    "__PACKAGE__->run_tests(@args)" and runs tests for the current package.

    You may specify an optional description or hash reference of constructor
    arguments to customize the test object:

        run_me( "load MD5" );
        run_me( { class => "Digest::MD5" } );
        run_me( "load MD5", { class => "Digest::MD5" } );

    See Test2::Roo::Class for more about the "run_tests" method.

    Alternatively, you can create a separate package (in the test file or in
    a separate .pm file) and run tests explicitly on that class.

        # t/test.t
        package MyTest;
        use Test2::Roo;

        use lib 't/lib';

        has class => (
            is       => 'ro',
            required => 1,
        );

        with 'MyTestRole';

        package main;
        use strictures;
        use Test2::V0;

        for my $c ( qw/Digest::MD5 Digest::SHA/ ) {
            MyTest->run_tests("Testing $c", { class => $c } );
        }

        done_testing;

EXPORTED FUNCTIONS
    Loading Test2::Roo exports subroutines into the calling package to
    declare and run tests.

  test
        test $label => sub { ... };

    The "test" function adds a subtest. The code reference will be called
    with the test object as its only argument.

    Tests are run in the order declared, so the order of tests from roles
    will depend on when they are composed relative to other test
    declarations.

  top_test
        top_test $label => sub { ... };

    The "top_test" function adds a "top level" test. Works exactly like
    "test" except it will not start a subtest. This is especially useful in
    very simple testing situations where the extra subtest level is just
    noise.

    So for example the following test

        # t/test.t
        use Test2::Roo;

        has class => (
            is       => 'ro',
            required => 1,
        );

        top_test basic => sub {
            my $self = shift;

            require_ok($self->class);
            isa_ok($self->class->new, $self->class);
        };

        for my $c ( qw/Digest::MD5 Digest::SHA/ ) {
            run_me("Testing $c", { class => $c } );
        }

        done_testing;

    produces the following TAP

        t/test.t ..
            ok 1 - require Digest::MD5;
            ok 2 - The object isa Digest::MD5
            1..2
        ok 1 - Testing Digest::MD5
            ok 1 - require Digest::SHA1;
            ok 2 - The object isa Digest::SHA1
            1..2
        ok 2 - Testing Digest::SHA1
        1..2
        ok
        All tests successful.
        Files=1, Tests=2,  0 wallclock secs ( 0.02 usr  0.01 sys +  0.06 cusr  0.00 csys =  0.09 CPU)
        Result: PASS

  run_me
        run_me;
        run_me( $description );
        run_me( $init_args   );
        run_me( $description, $init_args );

    The "run_me" function calls the "run_tests" method on the current
    package and passes all arguments to that method. It takes a description
    and/or a hash reference of constructor arguments.

DIFFERENCES FROM TEST::ROUTINE
    While this module was inspired by Test::Routine, it is not a drop-in
    replacement. Here is an overview of major differences:

    *   Test2::Roo uses Moo; Test::Routine uses Moose

    *   Loading Test2::Roo makes the importing package a class; in
        Test::Routine it becomes a role

    *   Loading Test2::Roo loads Test2::V0; Test::Routine does not

    *   In Test2::Roo, "run_test" is a method; in Test::Routine it is a
        function and takes arguments in a different order

    *   In Test2::Roo, all role composition must be explicit using "with";
        in Test::Routine, the "run_tests" command can also compose roles

    *   In Test2::Roo, test blocks become method modifiers hooked on an
        empty method; in Test::Routine, they become methods run via
        introspection

    *   In Test2::Roo, setup and teardown are done by modifying "setup" and
        "teardown" methods; in Test::Routine they are done by modifying
        "run_test"

SUPPORT
  Bugs / Feature Requests
    Please report any bugs or feature requests through the issue tracker at
    <https://rt.cpan.org/Public/Dist/Display.html?Name=Test2-Roo>. You will
    be notified automatically of any progress on your issue.

  Source Code
    This is open source software. The code repository is available for
    public review and contribution under the terms of the license.

    <https://gitlab.com/djerius/Test2-Roo>

      https://gitlab.com/djerius/Test2-Roo.git

AUTHOR
    David Golden <dagolden@cpan.org>

CONTRIBUTORS
    *   Arthur Axel 'fREW' Schmidt <frioux@gmail.com>

    *   Diab Jerius <djerius@cfa.harvard.edu>

COPYRIGHT AND LICENSE
    This software is Copyright (c) 2020 by David Golden, Diab Jerius
    (Smithsonian Astrophysical Observatory).

    This is free software, licensed under:

      The Apache License, Version 2.0, January 2004

