NAME

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

SYNOPSIS

        # see EXAMPLES for a full use case and caveats
    
        use Mock::Sub;
    
        my $foo = Mock::Sub->mock('Package::foo');
    
        # 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
    
        # create a mock object to reduce typing when multiple subs
        # are mocked
    
        my $mock = Mock::Sub->new;
    
        my $foo = $mock->mock('Package::foo');
        my $bar = $mock->mock('Package::bar');
    
        # have the mocked sub return something when it's called
    
        # a single scalar only
    
        my $foo = $mock->mock('Package::foo', return_value => 'True');
    
        # or return a list:
    
        $foo->return_value(1, 2, {a => 1});
    
        my $return = Package::foo;
    
        # have the mocked sub perform an action (void context again)
    
        my $foo = $mock->mock('Package::foo', side_effect => sub { die "eval catch"; });
        eval { Package::foo; };
        print 'died' if $@;
    
        # add a side-effect after instantiation
    
        $foo->side_effect(sub {print "hello, world!; });
    
        # extract the parameters the sub was called with (best if you know what
        # the original sub is expecting)
    
        my @args = $foo->called_with;
    
        # add/change/remove the side_effect after instantiation
    
        $foo->side_effect(sub {die;});
    
        # add/change/remove the return_value after instantiation
    
        $foo->return_value(50);
    
        # reset the mocked sub for re-use within the same scope
    
        $foo->reset;
    
        # restore original functionality to the sub (we unmock() by default on
        # DESTROY()
    
        $foo->unmock;

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");

METHODS

 new

    Instantiates and returns a new Mock::Sub object.

 mock('sub', %opts)

    Instantiates a new object on each call. '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.

    Options:

    return_value

      Set this to have the mocked sub return anything you wish (accepts a
      single scalar only. See return_value() method to return a list).

    side_effect

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

      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; }.

    keep_mock_on_destroy

      By default, we restore original sub functionality after the mock
      object goes out of scope. You can keep the mocked sub in place by
      setting this parameter to any true value.

 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. dies() if
    we're called before the mocked sub has been called.

 name

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

 side_effect($cref)

    Add (or remove) a side effect after instantiation. Same rules apply
    here as they do for the side_effect parameter.

 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

    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.

    Do not use a new mock object to call mock() in void context. There will
    be no object returned, thus no way to manually unmock() the sub, nor
    any way for automated cleanup to revert it back either.

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

SUPPORT

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

        perldoc Mock::Sub

ACKNOWLEDGEMENTS

    Python's MagicMock module.

LICENSE AND COPYRIGHT

    Copyright 2015 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.