The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Test::Mock::One - Mock the world with one object

VERSION

version 0.006

SYNOPSIS

    use Test::Mock::One;

    my $mock = Test::Mock::One->new(
        foo      => 'return value',
        bar      => 1,

        hashref  => \{ foo => 'bar' },
        arrayref => \[ foo => 'bar' ],
        code     => sub    { return your_special_function() },

    );

    $mock->foo;         # 'return value'
    $mock->bar;         # 1
    $mock->hashref;     # { foo => bar}
    $mock->arrayref;    # [ foo, bar ]
    $mock->code;        # executes your_special_function

    $mock->no->yes->work->it; # works fine

In combination with Sub::Override

    my $override = Sub::Override->new('Foo::Bar::baz', sub { Test::Mock::One(foo => 'bar') });

You now have Foo::Bar::baz that returns an object where the function foo returns bar.

Let's say you want to test a function that retrieves a user from a database and checks if it is active

    Package Foo;
    use Moose;

    has schema => ( is => 'ro' );
    sub check_user_in_db {
        my ($self, $username) = @_;
        my $user = $self->schema->resultset('User')->search_rs({username => $username})->first;
        return $user if $user->is_active;
        die "Unable to find user";
    }

    # In your test
    my $foo = Foo->new(
        schema => Test::Mock::One->new(
            schema => {
                resultset =>
                    { search_rs => { first => { is_active => undef } } }
            },
            'X-Mock-Strict' => 1,
        )
    );

    # Is the same as above, without Strict mode
    $foo = Foo->new(
        schema => Test::Mock::One->new(
            is_active => undef
            # This doesn't work with X-Mock-Strict enabled, because
            # the chain schema->resultset->search_rs->first cannot be
            # resolved
        )
    );

    throws_ok(
        sub {
            $foo->check_user_in_db('username');
        },
        qr/Unable to find user/,
        "username isn't active"
    );

    # A sunny day scenario would have been:
    my $mock = Foo->new(schema => Test::Mock::One->new());
    lives_ok(sub { $mock->check_user_in_db('username')}, "We found the user");

DESCRIPTION

Be able to mock many things with little code by using AUTOLOAD.

The problem this module tries to solve is to allow testing many things without having to write a monkey patch kind of solution in your test. Test::Mock::One tries to solve this by creating an object that can do "everything", and allows you to control specific behaviour. It works really well in combination with Sub::Override.

The methods copy the X-Mock attributes from their parent to themselves.

METHODS

new

Instantiate a new Test::Mock::One object

X-Mock-Strict

Boolean value. Undefined attributes will not be mocked and calling them makes us die.

X-Mock-ISA

Mock the ISA into the given class. Supported ways to mock the ISA:

    'X-Mock-ISA' => 'Some::Pkg',
    'X-Mock-ISA' => qr/Some::Pkg/,
    'X-Mock-ISA' => [qw(Some::Pkg Other::Pkg)],
    'X-Mock-ISA' => sub { return 0 },
    'X-Mock-ISA' => undef,
X-Mock-Stringify

Tell us how to stringify the object

    'X-Mock-Stringify' => 'My custom string',
    'X-Mock-Stringify' => sub { return "foo" },

isa

Returns true or false, depending on how X-Mock-ISA is set.

can

Returns true or false, depending on how X-Mock-Strict is set.

SEE ALSO

Sub::Override

AUTHOR

Wesley Schwengle <waterkip@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2017 by Wesley Schwengle.

This is free software, licensed under:

  The (three-clause) BSD License