NAME

   Mock::Sub - Mock package, object and standard subroutines, with unit
   testing in mind.

SYNOPSIS

       # see EXAMPLES for a full use case and caveats

       use Mock::Sub;

       # create the parent mock object

       my $mock = Mock::Sub->new;

       # mock some subs... all of the following are children under the
       # umbrella of the above $mock object we created

       my $foo = $mock->mock('Package::foo');
       my $bar = $mock->mock('Package::bar');

       # wait until the mocked sub is called

       Package::foo();

       # then...

       $foo->name;         # name of sub that's mocked
       $foo->called;       # was the sub called?
       $foo->called_count; # how many times was it called?
       $foo->called_with;  # array of params sent to sub

       # have the mocked sub return something when it's called (list or scalar).
       # See new() to find out how to set a return value once and have it used in
       # all child mocks

       $foo->return_value(1, 2, {a => 1});
       my @return = Package::foo;

       # have the mocked sub perform an action (the side effect function receives
       # the parameters sent into the mocked sub). See new() to find out how to
       # set side_effect up once, and have it copied to all child mocks

       $foo->side_effect( sub { die "eval catch" if @_; } );

       eval { Package::foo(1); };
       like ($@, qr/eval catch/, "side_effect worked with params");

       # extract the parameters the sub was called with (best if you know what
       # the original sub is expecting)

       my @args = $foo->called_with;

       # reset the mock object for re-use within the same scope (does not restore
       # the mocked sub)

       $foo->reset;

       # restore original functionality to the sub (we do this by default on
       # DESTROY()). This also calls reset() on the ojbect

       $foo->unmock;

       # re-mock a sub using the same object after unmocking (this is the only
       # time void context with mock() is permitted). Note that child mocks don't
       # take a sub parameter to mock()

       $foo->mock;

       # check if a sub is mocked

       my $state = $foo->state;

       # mock out a CORE:: function. Be warned that this *must* be done within
       # compile stage (BEGIN), and the function can NOT be unmocked prior
       # to the completion of program execution

       my ($mock, $caller);

       BEGIN {
           $mock = Mock::Sub->new;
           # core function caller() is now mocked permanently after the following line
           $caller = $mock->mock('caller');
       };

       $caller->return_value(55);
       caller(); # mocked caller() called

DESCRIPTION

   Easy to use and very lightweight module for mocking out sub calls. Very
   useful for testing areas of your own modules where getting coverage may
   be difficult due to nothing to test against, and/or to reduce test run
   time by eliminating the need to call subs that you really don't want or
   need to test.

EXAMPLE

   Here's a full example to get further coverage where it's difficult if
   not impossible to test certain areas of your code (eg: you have if/else
   statements, but they don't do anything but call other subs. You don't
   want to test the subs that are called, nor do you want to add
   statements to your code).

   Note that if the end subroutine you're testing is NOT Object Oriented
   (and you're importing them into your module that you're testing), you
   have to mock them as part of your own namespace (ie. instead of
   Other::first, you'd mock MyModule::first).

      # module you're testing:

       package MyPackage;

       use Other;
       use Exporter qw(import);
       @EXPORT_OK = qw(test);

       my $other = Other->new;

       sub test {
           my $arg = shift;

           if ($arg == 1){
               # how do you test this... there's no return etc.
               $other->first();
           }
           if ($arg == 2){
               $other->second();
           }
       }

       # your test file

       use MyPackage qw(test);
       use Mock::Sub;
       use Test::More tests => 2;

       my $mock = Mock::Sub->new;

       my $first = $mock->mock('Other::first');
       my $second = $mock->mock('Other::second');

       # coverage for first if() in MyPackage::test
       test(1);
       is ($first->called, 1, "1st if() statement covered");

       # coverage for second if()
       test(2);
       is ($second->called, 1, "2nd if() statement covered");

MOCK OBJECT METHODS

new(%opts)

   Instantiates and returns a new Mock::Sub object, ready to be used to
   start cteating mocked sub objects.

   Optional options:

   return_value

     Set this to have all mocked subs created with this mock object return
     anything you wish (accepts a single scalar only. See return_value()
     method to return a list and for further information). You can also
     set it in individual mocks only (see mock()).

   side_effect

     Set this in new() to have the side effect passed into all child mocks
     created with this object. See side_effect() method.

mock('sub', %opts)

   Instantiates and returns a new mock object on each call (calling in
   void context is not permitted). 'sub' is the name of the subroutine to
   mock (requires full package name if the sub isn't in main::.

   The mocked sub will return undef if a return value isn't set, or a side
   effect doesn't return anything.

   Optional options:

   Both return_value and side_effect can be set in this method to
   individualize each mock object. Set in new to have all mock objects use
   the same configuration.

   There's also return_value() and side_effect() methods if you want to
   set, change or remove these values after instantiation.

mocked_subs

   Returns a list of all subs that are currently mocked under the parent
   mock object.

mocked_objects

   Returns a list of all sub objects underneath the parent mock object,
   regardless if its sub is currently mocked or not.

mocked_state('Sub::Name')

   Returns whether a sub currently under the parent mock object is mocked
   or not. Croaks if there is no object with the sub name parameter.

SUB OBJECT METHODS

   These methods are for the children mocked sub objects returned from the
   parent mock object. See "MOCK OBJECT METHODS" for methods related to
   the parent mock object.

mock

   Re-mocks the sub within the object after calling unmock on it.

unmock

   Restores the original functionality back to the sub, and runs reset()
   on the object.

called

   Returns true if the sub being mocked has been called.

called_count

   Returns the number of times the mocked sub has been called.

called_with

   Returns an array of the parameters sent to the subroutine. croak()s if
   we're called before the mocked sub has been called.

mocked_state

   Returns true if the sub the object refers to is currently mocked, and
   false if not.

name

   Returns the full name of the sub being mocked, as entered into mock().

side_effect($cref)

   Add (or change/remove) a side effect after instantiation.

   Send in a code reference containing an action you'd like the mocked sub
   to perform (die() is useful for testing with eval()).

   The side effect function will receive all parameters sent into the
   mocked sub.

   You can use both side_effect() and return_value() params at the same
   time. side_effect will be run first, and then return_value. Note that
   if side_effect's last expression evaluates to any value whatsoever
   (even false), it will return that and return_value will be skipped.

   To work around this and have the side_effect run but still get the
   return_value thereafter, write your cref to evaluate undef as the last
   thing it does: sub { ...; undef; }.

return_value

   Add (or change, delete) the mocked sub's return value after
   instantiation. Can be a scalar or list. Send in undef to remove a
   previously set value.

reset

   Resets the functional parameters (return_value, side_effect), along
   with called() and called_count() back to undef/false.

NOTES

   This module has a backwards parent-child relationship. To use, you
   create a mock object using "PARENT MOCK OBJECT METHODS" new and mock
   methods, thereafter, you use the returned mocked sub object METHODS to
   perform the work.

   The parent mock object retains certain information and statistics of
   the child mocked objects (and the subs themselves).

   To mock CORE::GLOBAL functions, you *must* initiate within a BEGIN
   block (see SYNOPSIS for details). It is important that if you mock a
   CORE sub, it can't and won't be returned to its original state until
   after the entire program process tree exists. Period.

   I didn't make this a Test:: module (although it started that way)
   because I can see more uses than placing it into that category.

AUTHOR

   Steve Bertrand, <steveb at cpan.org>

BUGS

   Please report any bugs or requests at
   https://github.com/stevieb9/mock-sub/issues

REPOSITORY

   https://github.com/stevieb9/mock-sub

BUILD RESULTS

   Travis-CI: https://travis-ci.org/stevieb9/mock-sub

   CPAN Testers: http://matrix.cpantesters.org/?dist=Mock-Sub

   Coverage: https://coveralls.io/github/stevieb9/mock-sub

SUPPORT

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

       perldoc Mock::Sub

ACKNOWLEDGEMENTS

   Python's MagicMock module.

LICENSE AND COPYRIGHT

   Copyright 2016 Steve Bertrand.

   This program is free software; you can redistribute it and/or modify it
   under the terms of either: the GNU General Public License as published
   by the Free Software Foundation; or the Artistic License.

   See http://dev.perl.org/licenses/ for more information.