1Mock::MonkeyPatch(3pm)User Contributed Perl DocumentationMock::MonkeyPatch(3pm)
2
3
4

NAME

6       Mock::MonkeyPatch - Monkey patching with test mocking in mind
7

SYNOPSIS

9         {
10           package MyApp;
11
12           sub gen_item_id {
13             my $type = shift;
14             # calls external service and gets id for $type
15           }
16
17           sub build_item {
18             my $type = shift;
19             my $item = Item->new(type => $type);
20             $item->id(gen_item_id($type));
21             return $item;
22           }
23         }
24
25         use Test::More;
26         use MyApp;
27         use Mock::MonkeyPatch;
28
29         my $mock = Mock::MonkeyPatch->patch(
30           'MyApp::gen_item_id' => sub { 'abcd' }
31         );
32
33         my $item = MyApp::build_item('rubber_chicken');
34         is $item->id, 'abcd', 'building item calls MyApp::gen_random_id';
35         ok $mock->called, 'the mock was indeed called';
36         is_deeply $mock->arguments, ['rubber_chicken'], 'the mock was called with expected arguments';
37

DESCRIPTION

39       Mocking is a common tool, especially for testing.  By strategically
40       replacing a subroutine, one can isolate segments (units) of code to
41       test individually.  When this is done it is important to know that the
42       mocked sub was actually called and with what arguments it was called.
43
44       Mock::MonkeyPatch injects a subroutine in the place of an existing one.
45       It returns an object by which you can revisit the manner in which the
46       mocked subroutine was called.  Further when the object goes out of
47       scope (or when the "restore" method is called) the original subroutine
48       is replaced.
49

CONSTRUCTOR

51   patch
52         my $mock = Mock::MonkeyPatch->patch('MyPackage::foo' => sub { ... });
53         my $mock = Mock::MonkeyPatch->patch('MyPackage::foo' => sub { ... }, \%options);
54
55       Mock a subroutine and return a object to represent it.  Takes a fully
56       qualifed subroutine name, a subroutine reference to call in its place,
57       and optionally a hash reference of additional constructor arguments.
58
59       The replacement subroutine will be wrapped in a one that will store
60       calling data, then injected in place of the original.  Within the
61       replacement subroutine the original is available as the fully qualified
62       subroutine "Mock::MonkeyPatch::ORIGINAL".  This can be used to inject
63       behavior before, after, or even around the original.  This includes
64       munging the arguments passed to the origial (though the actual
65       arguments are what are stored).  For example usage, see "COOKBOOK".
66
67       Currently the optional hashref only accepts one option, an initial
68       value for "store_arguments" which is true if not given.
69
70       The wrapper will have the same prototype as the mocked function if one
71       exists.  The replacement need not have any prototype, the arguments
72       received by the wrapper will be passed to the given sub as they were
73       received.  (If this doesn't make any sense to you, don't worry about
74       it.)
75

METHODS

77   arguments
78         my $args = $mock->arguments;
79         my $args_second_time = $mock->arguments(1);
80
81       Returns an array reference containing the arguments that were passed to
82       the mocked subroutine (but see also "store_arguments").  Optionally an
83       integer may be passed which designates the call number to fetch
84       arguments in the same manner of indexing an array (zero indexed).  If
85       not given, 0 is assumed, representing the first time the mock was
86       called.  Returns "undef" if the mocked subroutine was not called (or
87       was not called enough times).
88
89         use Test::More;
90         is_deeply $mock->arguments, [1, 2, 3], 'called with the right arguments';
91
92   called
93         my $time_called = $mock->called;
94
95       Returns the number of times the mocked subroutine was called.  This
96       means that that there should be values available from "arguments" up to
97       the value of "$mock->called - 1".
98
99         use Test::More;
100         ok $mock->called, 'mock was called';
101         is $mock->called, 3, 'mock was called three times';
102
103   method_arguments
104         my $args = $mock->method_arguments;
105         my $args_third_time = $mock->method_arguments(2, 'MyClass');
106
107       A wrapper around "arguments" convenient for when the mocked subroutine
108       is called as a method.  Like "arguments" it returns a subroutine
109       reference, though it removes the first arguments which is the invocant.
110       It also can take a call number designation.
111
112       Additionally it takes a class name to test against the invocant as
113       "$invocant->isa('Class::Name')".  If the invocant is not an instance of
114       the class or a subclass thereof it returns "undef".
115
116         use Test::More;
117         is_deeply $mock->method_arguments(0, 'FrobberCo::Employee'),
118           ['some', 'arguments'], 'mock method called with known arguments on a FrobberCo::Employee instance';
119
120   reset
121         $mock = $mock->reset;
122
123       Reset the historical information stored in the mock, including
124       "arguments" and "called".  Returns the mock instance for chaining if
125       desired.
126
127       Note that this does not restore the original method. for that, see
128       "restore".
129
130         use Test::More;
131         is $mock->called, 3, 'called 3 times';
132         is $mock->reset->called, 0, 'called zero times after reset';
133
134   restore
135         $mock = $mock->restore;
136
137       Restore the original method to its original place in the symbol table.
138       This method is also called automatically when the object goes out of
139       scope and is garbage collected.  Returns the mock instance for chaining
140       if desired.  This method can only be called once!
141
142       Note that this does not reset historical information stored in the
143       mock, for that, see "reset".
144
145   store_arguments
146         $mock = $mock->store_arguments(0);
147
148       When true, the default if not passed to the constructor, arguments
149       passed to the mocked subroutine are stored and accessible later via
150       "arguments" and "method_arguments".  However sometimes this isn't
151       desirable, especially in cases where the reference count of items in
152       the arguments matter; notably when an object should be destroyed and
153       the destructor's behavior is important.  When this is true set
154       "store_arguments" to a false value and only an empty array reference
155       will be stored.
156
157       When used as a setter, it returns the mock instance for chaining if
158       desired.
159

COOKBOOK

161   Run code before the original
162       The original version of the mocked function (read: the code that was
163       available via the symbol at the time the mock was initiated) is
164       available via the fully qualified symbol "Mock::MonkeyPatch::ORIGINAL".
165       You can call this in your mock if for example you want to do some setup
166       before calling the function.
167
168         my $mock = $self->patch($symbol, sub {
169           # do some stuff before the original
170           do_mocked_stuff(@_);
171           # then call the original function/method
172           Mock::MonkeyPatch::ORIGINAL(@_);
173         });
174
175   Using ORIGINAL in a nonblocking environment
176       Since the "ORIGINAL" symbol is implemented via "local" if you want to
177       call it after leaving the scope you need to store a reference to the
178       function in a lexical.
179
180         my $mock = $self->patch($symbol, sub {
181           my @args = @_;
182           my $orig = \&Mock::MonkeyPatch::ORIGINAL;
183           Mojo::IOLoop->timer(1 => sub { $orig->(@args) });
184         });
185

SEE ALSO

187       •   Test::MockObject
188
189       •   Mock::Quick
190
191       •   Mock::Sub
192

SOURCE REPOSITORY

194       <http://github.com/jberger/Mock-MonkeyPatch>
195

AUTHOR

197       Joel Berger, <joel.a.berger@gmail.com>
198

CONTRIBUTORS

200       •   Doug Bell (preaction)
201
202       •   Brian Medley (bpmedley)
203
205       Copyright (C) 2016 by Joel Berger and "CONTRIBUTORS"
206
207       This library is free software; you can redistribute it and/or modify it
208       under the same terms as Perl itself.
209
210
211
212perl v5.36.0                      2022-07-22            Mock::MonkeyPatch(3pm)
Impressum