1Test2::Mock(3) User Contributed Perl Documentation Test2::Mock(3)
2
3
4
6 Test2::Mock - Module for managing mocked classes and instances.
7
9 This module lets you add and override methods for any package
10 temporarily. When the instance is destroyed it will restore the package
11 to its original state.
12
14 use Test2::Mock;
15 use MyClass;
16
17 my $mock = Test2::Mock->new(
18 track => $BOOL, # enable call tracking if desired
19 class => 'MyClass',
20 override => [
21 name => sub { 'fred' },
22 ...
23 ],
24 add => [
25 is_mocked => sub { 1 }
26 ...
27 ],
28 ...
29 );
30
31 # Unmock the 'name' sub
32 $mock->restore('name');
33
34 ...
35
36 $mock = undef; # Will remove all the mocking
37
40 $mock = Test2::Mock->new(class => $CLASS, ...)
41 This will create a new instance of Test2::Mock that manages mocking
42 for the specified $CLASS.
43
44 Any "Test2::Mock" method can be used as a constructor argument,
45 each should be followed by an arrayref of arguments to be used
46 within the method. For instance the "add()" method:
47
48 my $mock = Test2::Mock->new(
49 class => 'AClass',
50 add => [foo => sub { 'foo' }],
51 );
52
53 is identical to this:
54
55 my $mock = Test2::Mock->new(
56 class => 'AClass',
57 );
58 $mock->add(foo => sub { 'foo' });
59
60 $mock->track($bool)
61 Turn tracking on or off. Any sub added/overridden/set when tracking
62 is on will log every call in a hash retrievable via
63 "$mock->tracking". Changing the tracking toggle will not affect
64 subs already altered, but will affect any additional alterations.
65
66 $hashref = $mock->sub_tracking
67 The tracking data looks like this:
68
69 {
70 sub_name => [
71 {sub_name => $sub_name, sub_ref => $mock_subref, args => [... copy of @_ from the call ... ]},
72 ...,
73 ...,
74 ],
75 }
76
77 Unlike call_tracking, this lists all calls by sub, so you can
78 choose to only look at the sub specific calls.
79
80 Please note: The hashref items with the subname and args are shared
81 with call_tracking, modifying one modifies the other, so copy
82 first!
83
84 $arrayref = $mock->call_tracking
85 The tracking data looks like this:
86
87 [
88 {sub_name => $sub_name, sub_ref => $mock_subref, args => [... copy of @_ from the call ... ]},
89 ...,
90 ...,
91 ]
92
93 Unlike sub_tracking this lists all calls to any mocked sub, in the
94 order they were called. To filter by sub use sub_tracking.
95
96 Please note: The hashref items with the subname and args are shared
97 with sub_tracking, modifying one modifies the other, so copy first!
98
99 $mock->clear_sub_tracking()
100 $mock->clear_sub_tracking(\@subnames)
101 Clear tracking data. With no arguments ALL tracking data is
102 cleared. When arguments are provided then only those specific keys
103 will be cleared.
104
105 $mock->clear_call_tracking()
106 Clear all items from call_tracking.
107
108 $mock->add('symbol' => ..., 'symbol2' => ...)
109 $mock->override('symbol1' => ..., 'symbol2' => ...)
110 $mock->set('symbol1' => ..., 'symbol2' => ...)
111 "add()" and "override()" are the primary ways to add/modify methods
112 for a class. Both accept the exact same type of arguments. The
113 difference is that "override" will fail unless the symbol you are
114 overriding already exists, "add" on the other hand will fail if the
115 symbol does already exist.
116
117 "set()" was more recently added for cases where you may not know if
118 the sub already exists. These cases are rare, and set should be
119 avoided (think of it like 'no strict'). However there are valid use
120 cases, so it was added.
121
122 Note: Think of override as a push operation. If you call override
123 on the same symbol multiple times it will track that. You can use
124 "restore()" as a pop operation to go back to the previous mock.
125 "reset" can be used to remove all the mocking for a symbol.
126
127 Arguments must be a symbol name, with optional sigil, followed by a
128 new specification of the symbol. If no sigil is specified then '&'
129 (sub) is assumed. A simple example of overriding a sub:
130
131 $mock->override(foo => sub { 'overridden foo' });
132 my $val = $class->foo; # Runs our override
133 # $val is now set to 'overridden foo'
134
135 You can also simply provide a value and it will be wrapped in a sub
136 for you:
137
138 $mock->override( foo => 'foo' );
139
140 The example above will generate a sub that always returns the
141 string 'foo'.
142
143 There are three *special* values that can be used to generate
144 accessors:
145
146 $mock->add(
147 name => 'rw', # Generates a read/write accessor
148 age => 'ro', # Generates a read only accessor
149 size => 'wo', # Generates a write only accessor
150 );
151
152 If you want to have a sub that actually returns one of the three
153 special strings, or that returns a coderef, you can use a hashref
154 as the spec:
155
156 my $ref = sub { 'my sub' };
157 $mock->add(
158 rw_string => { val => 'rw' },
159 ro_string => { val => 'ro' },
160 wo_string => { val => 'wo' },
161 coderef => { val => $ref }, # the coderef method returns $ref each time
162 );
163
164 You can also override/add other symbol types, such as hash:
165
166 package Foo;
167 ...
168
169 $mock->add('%foo' => {a => 1});
170
171 print $Foo::foo{a}; # prints '1'
172
173 You can also tell mock to deduce the symbol type for the
174 add/override from the reference, rules are similar to glob
175 assignments:
176
177 $mock->add(
178 -foo => sub { 'foo' }, # Adds the &foo sub to the package
179 -foo => { foo => 1 }, # Adds the %foo hash to the package
180 -foo => [ 'f', 'o', 'o' ], # Adds the @foo array to the package
181 -foo => \"foo", # Adds the $foo scalar to the package
182 );
183
184 $mock->restore($SYMBOL)
185 Restore the symbol to what it was before the last override. If the
186 symbol was recently added this will remove it. If the symbol has
187 been overridden multiple times this will ONLY restore it to the
188 previous state. Think of "override" as a push operation, and
189 "restore" as the pop operation.
190
191 $mock->reset($SYMBOL)
192 Remove all mocking of the symbol and restore the original symbol.
193 If the symbol was initially added then it will be completely
194 removed.
195
196 $mock->orig($SYMBOL)
197 This will return the original symbol, before any mocking. For
198 symbols that were added this will return undef.
199
200 $mock->current($SYMBOL)
201 This will return the current symbol.
202
203 $mock->reset_all
204 Remove all added symbols, and restore all overridden symbols to
205 their originals.
206
207 $mock->add_constructor($NAME => $TYPE)
208 $mock->override_constructor($NAME => $TYPE)
209 This can be used to inject constructors. The first argument should
210 be the name of the constructor. The second argument specifies the
211 constructor type.
212
213 The "hash" type is the most common, all arguments are used to
214 create a new hash that is blessed.
215
216 hash => sub {
217 my ($class, %params) = @_;
218 return bless \%params, $class;
219 };
220
221 The "array" type is similar to the hash type, but accepts a list
222 instead of key/value pairs:
223
224 array => sub {
225 my ($class, @params) = @_;
226 return bless \@params, $class;
227 };
228
229 The "ref" type takes a reference and blesses it. This will modify
230 your original input argument.
231
232 ref => sub {
233 my ($class, $params) = @_;
234 return bless $params, $class;
235 };
236
237 The "ref_copy" type will copy your reference and bless the copy:
238
239 ref_copy => sub {
240 my ($class, $params) = @_;
241 my $type = reftype($params);
242
243 return bless {%$params}, $class
244 if $type eq 'HASH';
245
246 return bless [@$params], $class
247 if $type eq 'ARRAY';
248
249 croak "Not sure how to construct a '$class' from '$params'";
250 };
251
252 $mock->before($NAME, sub { ... })
253 This will replace the original sub $NAME with a new sub that calls
254 your custom code just before calling the original method. The
255 return from your custom sub is ignored. Your sub and the original
256 both get the unmodified arguments.
257
258 $mock->after($NAME, sub { ... })
259 This is similar to before, except your callback runs after the
260 original code. The return from your callback is ignored.
261
262 $mock->around($NAME, sub { ... })
263 This gives you the chance to wrap the original sub:
264
265 $mock->around(foo => sub {
266 my $orig = shift;
267 my $self = shift;
268 my (@args) = @_;
269
270 ...
271 $self->$orig(@args);
272 ...
273
274 return ...;
275 });
276
277 The original sub is passed in as the first argument, even before
278 $self. You are responsible for making sure your wrapper sub returns
279 the correct thing.
280
281 $mock->autoload
282 This will inject an "AUTOLOAD" sub into the class. This autoload
283 will automatically generate read-write accessors for any sub called
284 that does not already exist.
285
286 $mock->block_load
287 This will prevent the real class from loading until the mock is
288 destroyed. This will fail if the class is already loaded. This will
289 let you mock a class completely without loading the original
290 module.
291
292 $pm_file = $mock->file
293 This returns the relative path to the file for the module. This
294 corresponds to the %INC entry.
295
296 $bool = $mock->purge_on_destroy($bool)
297 When true, this will cause the package stash to be completely
298 obliterated when the mock object falls out of scope or is otherwise
299 destroyed. You do not normally want this.
300
301 $stash = $mock->stash
302 This returns the stash for the class being mocked. This is the
303 equivalent of:
304
305 my $stash = \%{"${class}\::"};
306
307 This saves you from needing to turn off strict.
308
309 $class = $mock->class
310 The class being mocked by this instance.
311
312 $p = $mock->parent
313 If you mock a class twice the first instance is the parent, the
314 second is the child. This prevents the parent from being destroyed
315 before the child, which would lead to a very unpleasant situation.
316
317 $c = $mock->child
318 Returns the child mock, if any.
319
321 The source code repository for Test2-Suite can be found at
322 <https://github.com/Test-More/Test2-Suite/>.
323
325 Chad Granum <exodist@cpan.org>
326
328 Chad Granum <exodist@cpan.org>
329
331 Copyright 2018 Chad Granum <exodist@cpan.org>.
332
333 This program is free software; you can redistribute it and/or modify it
334 under the same terms as Perl itself.
335
336 See <https://dev.perl.org/licenses/>
337
338
339
340perl v5.36.0 2022-07-22 Test2::Mock(3)