1Test::Spec::Mocks(3) User Contributed Perl Documentation Test::Spec::Mocks(3)
2
3
4
6 Test::Spec::Mocks - Object Simulation Plugin for Test::Spec
7
9 use Test::Spec;
10 use base qw(Test::Spec);
11
12 use My::RSS::Tool; # this is what we're testing
13 use LWP::UserAgent;
14
15 describe "RSS tool" => sub {
16 it "should fetch and parse an RSS feed" => sub {
17 my $xml = load_rss_fixture();
18 LWP::Simple->expects('get')->returns($xml);
19
20 # calls LWP::Simple::get, but returns our $xml instead
21 my @stories = My::RSS::Tool->run;
22
23 is_deeply(\@stories, load_stories_fixture());
24 };
25 };
26
28 Test::Spec::Mocks is a plugin for Test::Spec that provides mocking and
29 stubbing of objects, individual methods and plain subroutines on both
30 object instances and classes. This module is inspired by and heavily
31 borrows from Mocha, a library for the Ruby programming language. Mocha
32 itself is inspired by JMock.
33
34 Mock objects provide a way to simulate the behavior of real objects,
35 while providing consistent, repeatable results. This is very useful
36 when you need to test a function whose results are dependent upon an
37 external factor that is normally uncontrollable (like the time of day).
38 Mocks also allow you to test your code in isolation, a tenet of unit
39 testing.
40
41 There are many other reasons why mock objects might come in handy. See
42 the Mock objects <http://en.wikipedia.org/wiki/Mock_object> article at
43 Wikipedia for lots more examples and more in-depth coverage of the
44 philosophy behind object mocking.
45
46 Ecosystem
47 Test::Spec::Mocks is currently only usable from within tests built with
48 the Test::Spec BDD framework.
49
50 Terminology
51 Familiarize yourself with these terms:
52
53 • Stub object
54
55 A stub object is an object created specifically to return canned
56 responses for a specific set of methods. These are created with the
57 stub function.
58
59 • Mock object
60
61 Mock objects are similar to stub objects, but are programmed with
62 both prepared responses and expectations for how they will be
63 called. If the expectations are not met, they raise an exception to
64 indicate that the test failed. Mock objects are created with the
65 mock function.
66
67 • Stubbed method
68
69 Stubbed methods temporarily replace existing methods on a class or
70 object instance. This is useful when you only want to override a
71 subset of an object or class's behavior. For example, you might
72 want to override the "do" method of a DBI handle so it doesn't make
73 changes to your database, but still need the handle to respond as
74 usual to the "quote" method. You'll stub methods using the stubs
75 method.
76
77 • Mocked method
78
79 If you've been reading up to this point, this will be no surprise.
80 Mocked methods are just like stubbed methods, but they come with
81 expectations that will raise an exception if not met. For example,
82 you can mock a "save" method on an object to ensure it is called by
83 the code you are testing, while preventing the data from actually
84 being committed to disk in your test. Use the expects method to
85 create mock methods.
86
87 • "stub", "mock"
88
89 Depending on context, these can refer to stubbed objects and
90 methods, or mocked objects and methods, respectively.
91
92 Using stub objects (anonymous stubs)
93 Sometimes the code you're testing requires that you pass it an object
94 that conforms to a specific interface. For example, you are testing a
95 console prompting library, but you don't want to require a real person
96 to stand by, waiting to type answers into the console. The library
97 requires an object that returns a string when the "read_line" method is
98 called.
99
100 You could create a class specifically for returning test console input.
101 But why do that? You can create a stub object in one line:
102
103 describe "An Asker" => sub {
104 my $asker = Asker->new;
105
106 it "returns true when a yes_or_no question is answered 'yes'" => sub {
107 my $console_stub = stub(read_line => "yes");
108 # $console_stub->read_line returns "yes"
109 ok( $asker->yes_or_no($console_stub, "Am I awesome?") );
110 };
111
112 it "returns false when a yes_or_no question is answered 'no'" => sub {
113 my $console_stub = stub(read_line => "no");
114 ok( ! $asker->yes_or_no($console_stub, "Am I second best?") );
115 };
116 };
117
118 Stubs can also take subroutine references. This is useful when the
119 behavior you need to mimic is a little more complex.
120
121 it "keeps asking until it gets an answer" => sub {
122 my @answers = (undef, "yes");
123 my $console_stub = stub(read_line => sub { shift @answers });
124 # when console_stub is called the first time, it returns undef
125 # the second time returns "yes"
126 ok( $asker->yes_or_no($console_stub, "Do I smell nice?") );
127 };
128
129 Using mock objects
130 If you want to take your tests one step further, you can use mock
131 objects instead of stub objects. Mocks ensure the methods you expect to
132 be called actually are called. If they aren't, the mock will raise an
133 exception which causes your test to fail.
134
135 In this example, we are testing that "read_line" is called once and
136 only once (the default for mocks).
137
138 it "returns true when a yes_or_no question is answered 'yes'" => sub {
139 my $console_mock = mock();
140 $console_mock->expects('read_line')
141 ->returns("yes");
142 # $console_mock->read_line returns "yes"
143 ok( $asker->yes_or_no($console_mock, "Am I awesome?") );
144 };
145
146 If Asker's "yes_or_no" method doesn't call "read_line" on our mock
147 exactly one time, the test would fail with a message like:
148
149 expected read_line to be called exactly 1 time, but it was called 0 times
150
151 You can specify how many times your mock should be called with
152 "exactly":
153
154 it "keeps asking until it gets an answer" => sub {
155 my @answers = (undef, "yes");
156 my $console_mock = mock();
157 $console_mock->expects('read_line')
158 ->returns(sub { shift @answers })
159 ->exactly(2);
160 # when console_mock is called the first time, it returns undef
161 # the second time returns "yes"
162 ok( $asker->yes_or_no($console_mock, "Do I smell nice?") );
163 };
164
165 If you want something more flexible than "exactly", you can choose from
166 "at_least", "at_most", "any_number" and others. See "EXPECTATION
167 ADJUSTMENT METHODS".
168
169 Stubbing methods
170 Sometimes you want to override just a small subset of an object's
171 behavior.
172
173 describe "The old audit system" => sub {
174 my $dbh;
175 before sub { $dbh = SomeExternalClass->get_dbh };
176
177 it "executes the expected sql" => sub {
178 my $sql;
179 $dbh->stubs(do => sub { $sql = shift; return 1 });
180
181 # $dbh->do("foo") now sets $sql to "foo"
182 # $dbh->quote still does what it normally would
183
184 audit_event($dbh, "server crash, oh noes!!");
185
186 like( $sql, qr/insert into audit_event.*'server crash, oh noes!!!'/ );
187 };
188 };
189
190 You can also stub class methods:
191
192 # 1977-05-26T14:11:55
193 my $event_datetime = DateTime->new(from_epoch => 0xdeafcab);
194
195 it "should tag each audit event with the current time" => sub {
196 DateTime->stubs('now' => sub { $event_datetime });
197 is( audit_timestamp(), '19770526.141155' );
198 };
199
200 Mocking methods
201 Mocked methods are to stubbed methods as mock objects are to stub
202 objects.
203
204 it "executes the expected sql" => sub {
205 $dbh->expects('do')->returns(sub { $sql = shift; return 1 });
206
207 # $dbh->do("foo") now sets $sql to "foo"
208 # $dbh->quote still does what it normally would
209
210 audit_event($dbh, "server crash, oh noes!!");
211 like( $sql, qr/insert into audit_event.*'server crash, oh noes!!!'/ );
212
213 # if audit_event doesn't call $dbh->do exactly once, KABOOM!
214 };
215
217 stub()
218 stub($method_name => $result, ...)
219 stub($method_name => sub { $result }, ...)
220 stub({ $method_name => $result, ... })
221 Returns a new anonymous stub object. Takes a list of
222 $method_name/$result pairs or a reference to a hash containing the
223 same. Each $method_name listed is stubbed to return the associated
224 value ($result); or if the value is a subroutine reference, it is
225 stubbed in-place (the subroutine becomes the method).
226
227 Examples:
228
229 # A blank object with no methods.
230 # Gives a true response to ref() and blessed().
231 my $blank = stub();
232
233 # Static responses to width() and height():
234 my $rect = stub(width => 5, height => 5);
235
236 # Dynamic response to area():
237 my $radius = 1.0;
238 my $circle_stub = stub(area => sub { PI * $radius * $radius });
239
240 You can also stub more methods, just like with any other object:
241
242 my $rect = stub(width => 5, height => 5);
243 $rect->stubs(area => sub { my $self = shift; $self->width * $self->height });
244
245 $thing->stubs($method_name)
246 $thing->stubs($method_name => $result)
247 $thing->stubs($method_name => sub { $result })
248 $thing->stubs({ $method_name => $result })
249 Stubs one or more methods on an existing class or instance, $thing.
250
251 If passed only one (non-hash) argument, it is interpreted as a
252 method name. The return value of the stubbed method will be
253 "undef".
254
255 Otherwise, the arguments are a list of $method_name and $result
256 pairs, either as a flat list or as a hash reference. Each method is
257 installed onto $thing, and returns the specified result. If the
258 result is a subroutine reference, it will be called for every
259 invocation of the method.
260
261 mock()
262 Returns a new blank, anonymous mock object, suitable for mocking
263 methods with expects().
264
265 my $rect = mock();
266 $rect->expects('area')->returns(100);
267
268 $thing->expects($method)
269 Installs a mock method named $method onto the class or object
270 $thing and returns an Test::Spec::Mocks::Expectation object, which
271 you can use to set the return value with "returns()" and other
272 expectations. By default, the method is expected to be called
273 at_least_once.
274
275 If the expectation is not met before the enclosing example
276 completes, the mocked method will raise an exception that looks
277 something like:
278
279 expected foo to be called exactly 1 time, but it was called 0 times
280
282 These are methods of the Test::Spec::Mocks::Expectation class, which
283 you'll receive by calling "expects()" on a class or object instance.
284
285 returns( $result )
286 returns( @result )
287 returns( \&callback )
288 Configures the mocked method to return the specified result when
289 called. If passed a subroutine reference, the subroutine will be
290 executed when the method is called, and the result is the return
291 value.
292
293 $rect->expects('height')->returns(5);
294 # $rect->height ==> 5
295
296 @points = ( [0,0], [1,0], [1,1], [1,0] );
297 $rect->expects('points')->returns(@points);
298 # (@p = $rect->points) ==> ( [0,0], [1,0], [1,1], [1,0] )
299 # ($p = $rect->points) ==> 4
300
301 @points = ( [0,0], [1,0], [1,1], [1,0] );
302 $rect->expects('next_point')->returns(sub { shift @points });
303 # $rect->next_point ==> [0,0]
304 # $rect->next_point ==> [1,0]
305 # ...
306
307 exactly($N)
308 Configures the mocked method so that it must be called exactly $N
309 times.
310
311 never
312 Configures the mocked method so that it must never be called.
313
314 once
315 Configures the mocked method so that it must be called exactly one
316 time.
317
318 at_least($N)
319 Configures the mocked method so that it must be called at least $N
320 times.
321
322 at_least_once
323 Configures the mocked method so that it must be called at least 1
324 time. This is just syntactic sugar for at_least(1).
325
326 at_most($N)
327 Configures the mocked method so that it must be called no more than
328 $N times.
329
330 at_most_once
331 Configures the mocked method so that it must be called either zero
332 or 1 times.
333
334 maybe
335 An alias for "at_most_once".
336
337 any_number
338 Configures the mocked method so that it can be called zero or more
339 times.
340
341 times
342 A syntactic sugar no-op:
343
344 $io->expects('print')->exactly(3)->times;
345
346 This method is alpha and will probably change in a future release.
347
348 with(@arguments) / with_eq(@arguments)
349 Configures the mocked method so that it must be called with
350 arguments as specified. The arguments will be compared using the
351 "eq" operator, so it works for most scalar values with no problem.
352 If you want to check objects here, they must be the exact same
353 instance or you must overload the "eq" operator to provide the
354 behavior you desire.
355
356 with_deep(@arguments)
357 Similar to "with_eq" except the arguments are compared using
358 Test::Deep: scalars are compared by value, arrays and hashes must
359 have the same elements and references must be blessed into the same
360 class.
361
362 $cache->expects('set')
363 ->with_deep($customer_id, { name => $customer_name });
364
365 Use Test::Deep's comparison functions for more flexibility:
366
367 use Test::Deep::NoTest ();
368 $s3->expects('put')
369 ->with_deep('test-bucket', 'my-doc', Test::Deep::ignore());
370
371 raises($exception)
372 Configures the mocked method so that it raises $exception when
373 called.
374
376 verify
377 Allows you to verify manually that the expectation was met. If the
378 expectation has not been met, the method dies with an error message
379 containing specifics of the failure. Returns true otherwise.
380
381 problems
382 If the expectation has not been met, returns a list of problem
383 description strings. Otherwise, returns an empty list.
384
386 Memory leaks
387 Because of the way the mock objects ("stubs", "stub", "expects",
388 and "mock") are integrated into the Test::Spec runtime they will
389 leak memory. It is not recommended to use the Test::Spec mocks in
390 any long-running program.
391
392 Patches welcome.
393
395 There are other less sugary mocking systems for Perl, including
396 Test::MockObject and Test::MockObject::Extends.
397
398 This module is a plugin for Test::Spec. It is inspired by Mocha
399 <http://mocha.rubyforge.org/>.
400
401 The Wikipedia article Mock object
402 <http://en.wikipedia.org/wiki/Mock_object> is very informative.
403
405 Philip Garrett, <philip.garrett@icainformatics.com>
406
408 Copyright (c) 2011 by Informatics Corporation of America.
409
410 This program is free software; you can redistribute it and/or modify it
411 under the same terms as Perl itself.
412
413
414
415perl v5.34.0 2022-01-21 Test::Spec::Mocks(3)