NAME

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

VERSION

version 0.005

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

Ways to override specific behaviours

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-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