File Coverage

blib/lib/Mock/Sub.pm
Criterion Covered Total %
statement 58 58 100.0
branch 10 10 100.0
condition n/a
subroutine 11 13 84.6
pod 5 5 100.0
total 84 86 97.6


line stmt bran cond sub pod time code
1             package Mock::Sub;
2 15     15   454207 use 5.006;
  15         58  
3 15     15   80 use strict;
  15         23  
  15         314  
4 15     15   71 use warnings;
  15         30  
  15         608  
5              
6 15     15   76 use Carp qw(croak);
  15         26  
  15         1011  
7 15     15   8357 use Mock::Sub::Child;
  15         44  
  15         562  
8 15     15   81 use Scalar::Util qw(weaken);
  15         28  
  15         9562  
9              
10             our $VERSION = '1.05';
11              
12             sub new {
13 49     49 1 3579 my $self = bless {}, shift;
14 49         103 %{ $self } = @_;
  49         155  
15 49         119 return $self;
16             }
17             sub mock {
18 61     61 1 5606 my $self = shift;
19 61         96 my $sub = shift;
20              
21 61 100       194 if (ref($self) ne 'Mock::Sub'){
22 3         459 croak
23             "calling mock() on the Mock::Sub class is no longer permitted. " .
24             "create a new mock object with Mock::Sub->new;, then call mock " .
25             "with my \$sub_object = \$mock->mock('sub_name'); ";
26             }
27 58         119 my %p = @_;
28 58         178 for (keys %p){
29 19         123 $self->{$_} = $p{$_};
30             }
31              
32 58 100       291 if (! defined wantarray){
33 1         94 croak "\n\ncalling mock() in void context isn't allowed. ";
34             }
35              
36 57         234 my $child = Mock::Sub::Child->new;
37              
38 57         245 $child->side_effect($self->{side_effect});
39 55         265 $child->return_value($self->{return_value});
40              
41 55         186 $self->{objects}{$sub}{obj} = $child;
42 55         170 $child->mock($sub);
43              
44             # remove the REFCNT to the child, or else DESTROY won't be called
45 55         171 weaken $self->{objects}{$sub}{obj};
46              
47 55         151 return $child;
48             }
49             sub mocked_subs {
50 3     3 1 12 my $self = shift;
51              
52 3         4 my @names;
53              
54 3         3 for (keys %{ $self->{objects} }) {
  3         12  
55 9 100       18 if ($self->mocked_state($_)){
56 8         17 push @names, $_;
57             }
58             }
59 3         13 return @names;
60             }
61             sub mocked_objects {
62 2     2 1 7 my $self = shift;
63              
64 2         4 my @mocked;
65 2         4 for (keys %{ $self->{objects} }){
  2         7  
66 6         12 push @mocked, $self->{objects}{$_}{obj};
67             }
68 2         9 return @mocked;
69             }
70             sub mocked_state {
71 13     13 1 24 my ($self, $sub) = @_;
72              
73 13 100       30 if (! $sub){
74 1         97 croak "calling mocked_state() on a Mock::Sub object requires a sub " .
75             "name to be passed in as its only parameter. ";
76             }
77              
78 12         16 eval {
79 12         47 my $test = $self->{objects}{$sub}{obj}->mocked_state();
80             };
81 12 100       37 if ($@){
82 1         153 croak "can't call mocked_state() on the class if the sub hasn't yet " .
83             "been mocked. ";
84             }
85 11         28 return $self->{objects}{$sub}{obj}->mocked_state;
86             }
87       0     sub DESTROY {
88             }
89       0     sub __end {}; # vim fold placeholder
90              
91             1;
92             =head1 NAME
93              
94             Mock::Sub - Mock package, object and standard subroutines, with unit testing in mind.
95              
96             =for html
97            
98             Coverage Status
99              
100             =head1 SYNOPSIS
101              
102             # see EXAMPLES for a full use case and caveats
103              
104             use Mock::Sub;
105              
106             # create the parent mock object
107              
108             my $mock = Mock::Sub->new;
109              
110             # mock some subs... all of the following are children under the
111             # umbrella of the above $mock object we created
112              
113             my $foo = $mock->mock('Package::foo');
114             my $bar = $mock->mock('Package::bar');
115              
116             # wait until a mocked sub is called
117              
118             Package::foo();
119              
120             # then...
121              
122             $foo->name; # name of sub that's mocked
123             $foo->called; # was the sub called?
124             $foo->called_count; # how many times was it called?
125             $foo->called_with; # array of params sent to sub
126              
127             # have the mocked sub return something when it's called (list or scalar).
128             # See new() to find out how to set a return value once and have it used in
129             # all child mocked subs
130              
131             $foo->return_value(1, 2, {a => 1});
132             my @return = Package::foo;
133              
134             # have the mocked sub perform an action (the side effect function receives
135             # the parameters sent into the mocked sub). See new() to find out how to
136             # set side_effect up once, and have it copied to all child mocked subs
137              
138             $foo->side_effect( sub { die "eval catch" if @_; } );
139              
140             eval { Package::foo(1); };
141             like ($@, qr/eval catch/, "side_effect worked with params");
142              
143             # extract the parameters the sub was called with (best if you know what
144             # the original sub is expecting)
145              
146             my @args = $foo->called_with;
147              
148             # reset the mock object for re-use within the same scope (does not restore
149             # the mocked sub)
150              
151             $foo->reset;
152              
153             # restore original functionality to the sub (we do this by default on
154             # DESTROY()). This also calls reset() on the ojbect
155              
156             $foo->unmock;
157              
158             # re-mock a sub using the same object after unmocking (this is the only
159             # time void context with mock() is permitted). Note that child mocks don't
160             # take a sub parameter to mock(), as they simply re-mock their original sub
161              
162             $foo->mock;
163              
164             # check if a sub is mocked
165              
166             my $state = $foo->state;
167              
168             # mock out a CORE:: function. Be warned that this *must* be done within
169             # compile stage (BEGIN), and the function can NOT be unmocked prior
170             # to the completion of program execution
171              
172             my ($mock, $caller);
173              
174             BEGIN {
175             $mock = Mock::Sub->new;
176             # core function caller() is now mocked permanently after the following line
177             $caller = $mock->mock('caller');
178             };
179              
180             $caller->return_value(55);
181             caller(); # mocked caller() called
182              
183             =head1 DESCRIPTION
184              
185             Easy to use and very lightweight module for mocking out sub calls.
186             Very useful for testing areas of your own modules where getting coverage may
187             be difficult due to nothing to test against, and/or to reduce test run time by
188             eliminating the need to call subs that you really don't want or need to test.
189              
190             =head1 EXAMPLE
191              
192             Here's a full example to get further coverage where it's difficult if not
193             impossible to test certain areas of your code (eg: you have if/else statements,
194             but they don't do anything but call other subs. You don't want to test the
195             subs that are called, nor do you want to add statements to your code).
196              
197             Note that if the end subroutine you're testing is NOT Object Oriented (and
198             you're importing them into your module that you're testing), you have to mock
199             them as part of your own namespace (ie. instead of Other::first, you'd mock
200             MyModule::first).
201              
202             # module you're testing:
203              
204             package MyPackage;
205            
206             use Other;
207             use Exporter qw(import);
208             @EXPORT_OK = qw(test);
209            
210             my $other = Other->new;
211              
212             sub test {
213             my $arg = shift;
214            
215             if ($arg == 1){
216             # how do you test this... there's no return etc.
217             $other->first();
218             }
219             if ($arg == 2){
220             $other->second();
221             }
222             }
223              
224             # your test file
225              
226             use MyPackage qw(test);
227             use Mock::Sub;
228             use Test::More tests => 2;
229              
230             my $mock = Mock::Sub->new;
231              
232             my $first = $mock->mock('Other::first');
233             my $second = $mock->mock('Other::second');
234              
235             # coverage for first if() in MyPackage::test
236             test(1);
237             is ($first->called, 1, "1st if() statement covered");
238              
239             # coverage for second if()
240             test(2);
241             is ($second->called, 1, "2nd if() statement covered");
242              
243             =head1 MOCK OBJECT METHODS
244              
245             =head2 C
246              
247             Instantiates and returns a new C object, ready to be used to start
248             cteating mocked sub objects.
249              
250             Optional options:
251              
252             =over 4
253              
254             =item C
255              
256             Set this to have all mocked subs created with this mock object return anything
257             you wish (accepts a single scalar only. See C method to return
258             a list and for further information). You can also set it in individual mocks
259             only (see C).
260              
261             =item C
262              
263             Set this in C to have the side effect passed into all child mocks
264             created with this object. See C method.
265              
266             =back
267              
268             =head2 C
269              
270             Instantiates and returns a new mock object on each call (calling in
271             void context is not permitted). 'sub' is the name of the subroutine to mock
272             (requires full package name if the sub isn't in C.
273              
274             The mocked sub will return undef if a return value isn't set, or a side effect
275             doesn't return anything.
276              
277             Optional options:
278              
279             Both C and C can be set in this method to
280             individualize each mock object. Set in C to have all mock objects use
281             the same configuration.
282              
283             There's also C and C methods if you want to
284             set, change or remove these values after instantiation.
285              
286             =head2 mocked_subs
287              
288             Returns a list of all subs that are currently mocked under the parent mock
289             object.
290              
291             =head2 mocked_objects
292              
293             Returns a list of all sub objects underneath the parent mock object, regardless
294             if its sub is currently mocked or not.
295              
296             =head2 mocked_state('Sub::Name')
297              
298             Returns whether a sub currently under the parent mock object is mocked or not.
299             Croaks if there is no object with the sub name parameter.
300              
301             =head1 SUB OBJECT METHODS
302              
303             These methods are for the children mocked sub objects returned from the
304             parent mock object. See L for methods related
305             to the parent mock object.
306              
307             =head2 C
308              
309             Re-mocks the sub within the object after calling C on it.
310              
311             =head2 C
312              
313             Restores the original functionality back to the sub, and runs C on
314             the object.
315              
316             =head2 C
317              
318             Returns true if the sub being mocked has been called.
319              
320             =head2 C
321              
322             Returns the number of times the mocked sub has been called.
323              
324             =head2 C
325              
326             Returns an array of the parameters sent to the subroutine. C if
327             we're called before the mocked sub has been called.
328              
329             =head2 C
330              
331             Returns true if the sub the object refers to is currently mocked, and false if
332             not.
333              
334             =head2 C
335              
336             Returns the full name of the sub being mocked, as entered into C.
337              
338             =head2 C
339              
340             Add (or change/remove) a side effect after instantiation.
341              
342             Send in a code reference containing an action you'd like the
343             mocked sub to perform (C is useful for testing with C).
344              
345             The side effect function will receive all parameters sent into the mocked sub.
346              
347             You can use both C and C params at the same
348             time. C will be run first, and then C. Note that if
349             C's last expression evaluates to any value whatsoever
350             (even false), it will return that and C will be skipped.
351              
352             To work around this and have the side_effect run but still get the
353             return_value thereafter, write your cref to evaluate undef as the last thing
354             it does: C.
355              
356             =head2 C
357              
358             Add (or change, delete) the mocked sub's return value after instantiation.
359             Can be a scalar or list. Send in C to remove a previously set value.
360              
361             =head2 C
362              
363             Resets the functional parameters (C, C), along
364             with C and C back to undef/false.
365              
366             =head1 NOTES
367              
368             This module has a backwards parent-child relationship. To use, you create a
369             mock object using L C and C methods,
370             thereafter, you use the returned mocked sub object L to perform the
371             work.
372              
373             The parent mock object retains certain information and statistics of the child
374             mocked objects (and the subs themselves).
375              
376             To mock CORE::GLOBAL functions, you *must* initiate within a C block
377             (see C for details). It is important that if you mock a CORE sub,
378             it can't and won't be returned to its original state until after the entire
379             program process tree exists. Period.
380              
381             I didn't make this a C module (although it started that way) because
382             I can see more uses than placing it into that category.
383              
384             =head1 AUTHOR
385              
386             Steve Bertrand, C<< >>
387              
388             =head1 BUGS
389              
390             Please report any bugs or requests at
391             L
392              
393             =head1 REPOSITORY
394              
395             L
396              
397             =head1 BUILD RESULTS
398              
399             CPAN Testers: L
400              
401             =head1 SUPPORT
402              
403             You can find documentation for this module with the perldoc command.
404              
405             perldoc Mock::Sub
406              
407             =head1 ACKNOWLEDGEMENTS
408              
409             Python's MagicMock module.
410              
411             =head1 LICENSE AND COPYRIGHT
412              
413             Copyright 2016 Steve Bertrand.
414              
415             This program is free software; you can redistribute it and/or modify it
416             under the terms of either: the GNU General Public License as published
417             by the Free Software Foundation; or the Artistic License.
418              
419             See L for more information.
420              
421              
422             =cut
423              
424             1; # End of Mock::Sub
425