python/mock-1.0.0/docs/compare.txt

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:eb69bbeae4cf
1 =========================
2 Mock Library Comparison
3 =========================
4
5
6 .. testsetup::
7
8 def assertEqual(a, b):
9 assert a == b, ("%r != %r" % (a, b))
10
11 def assertRaises(Exc, func):
12 try:
13 func()
14 except Exc:
15 return
16 assert False, ("%s not raised" % Exc)
17
18 sys.modules['somemodule'] = somemodule = mock.Mock(name='somemodule')
19 class SomeException(Exception):
20 some_method = method1 = method2 = None
21 some_other_object = SomeObject = SomeException
22
23
24 A side-by-side comparison of how to accomplish some basic tasks with mock and
25 some other popular Python mocking libraries and frameworks.
26
27 These are:
28
29 * `flexmock <http://pypi.python.org/pypi/flexmock>`_
30 * `mox <http://pypi.python.org/pypi/mox>`_
31 * `Mocker <http://niemeyer.net/mocker>`_
32 * `dingus <http://pypi.python.org/pypi/dingus>`_
33 * `fudge <http://pypi.python.org/pypi/fudge>`_
34
35 Popular python mocking frameworks not yet represented here include
36 `MiniMock <http://pypi.python.org/pypi/MiniMock>`_.
37
38 `pMock <http://pmock.sourceforge.net/>`_ (last release 2004 and doesn't import
39 in recent versions of Python) and
40 `python-mock <http://python-mock.sourceforge.net/>`_ (last release 2005) are
41 intentionally omitted.
42
43 .. note::
44
45 A more up to date, and tested for all mock libraries (only the mock
46 examples on this page can be executed as doctests) version of this
47 comparison is maintained by Gary Bernhardt:
48
49 * `Python Mock Library Comparison
50 <http://garybernhardt.github.com/python-mock-comparison/>`_
51
52 This comparison is by no means complete, and also may not be fully idiomatic
53 for all the libraries represented. *Please* contribute corrections, missing
54 comparisons, or comparisons for additional libraries to the `mock issue
55 tracker <https://code.google.com/p/mock/issues/list>`_.
56
57 This comparison page was originally created by the `Mox project
58 <https://code.google.com/p/pymox/wiki/MoxComparison>`_ and then extended for
59 `flexmock and mock <http://has207.github.com/flexmock/compare.html>`_ by
60 Herman Sheremetyev. Dingus examples written by `Gary Bernhadt
61 <http://garybernhardt.github.com/python-mock-comparison/>`_. fudge examples
62 provided by `Kumar McMillan <http://farmdev.com/>`_.
63
64 .. note::
65
66 The examples tasks here were originally created by Mox which is a mocking
67 *framework* rather than a library like mock. The tasks shown naturally
68 exemplify tasks that frameworks are good at and not the ones they make
69 harder. In particular you can take a `Mock` or `MagicMock` object and use
70 it in any way you want with no up-front configuration. The same is also
71 true for Dingus.
72
73 The examples for mock here assume version 0.7.0.
74
75
76 Simple fake object
77 ~~~~~~~~~~~~~~~~~~
78
79 .. doctest::
80
81 >>> # mock
82 >>> my_mock = mock.Mock()
83 >>> my_mock.some_method.return_value = "calculated value"
84 >>> my_mock.some_attribute = "value"
85 >>> assertEqual("calculated value", my_mock.some_method())
86 >>> assertEqual("value", my_mock.some_attribute)
87
88 ::
89
90 # Flexmock
91 mock = flexmock(some_method=lambda: "calculated value", some_attribute="value")
92 assertEqual("calculated value", mock.some_method())
93 assertEqual("value", mock.some_attribute)
94
95 # Mox
96 mock = mox.MockAnything()
97 mock.some_method().AndReturn("calculated value")
98 mock.some_attribute = "value"
99 mox.Replay(mock)
100 assertEqual("calculated value", mock.some_method())
101 assertEqual("value", mock.some_attribute)
102
103 # Mocker
104 mock = mocker.mock()
105 mock.some_method()
106 mocker.result("calculated value")
107 mocker.replay()
108 mock.some_attribute = "value"
109 assertEqual("calculated value", mock.some_method())
110 assertEqual("value", mock.some_attribute)
111
112 ::
113
114 >>> # Dingus
115 >>> my_dingus = dingus.Dingus(some_attribute="value",
116 ... some_method__returns="calculated value")
117 >>> assertEqual("calculated value", my_dingus.some_method())
118 >>> assertEqual("value", my_dingus.some_attribute)
119
120 ::
121
122 >>> # fudge
123 >>> my_fake = (fudge.Fake()
124 ... .provides('some_method')
125 ... .returns("calculated value")
126 ... .has_attr(some_attribute="value"))
127 ...
128 >>> assertEqual("calculated value", my_fake.some_method())
129 >>> assertEqual("value", my_fake.some_attribute)
130
131
132 Simple mock
133 ~~~~~~~~~~~
134
135 .. doctest::
136
137 >>> # mock
138 >>> my_mock = mock.Mock()
139 >>> my_mock.some_method.return_value = "value"
140 >>> assertEqual("value", my_mock.some_method())
141 >>> my_mock.some_method.assert_called_once_with()
142
143 ::
144
145 # Flexmock
146 mock = flexmock()
147 mock.should_receive("some_method").and_return("value").once
148 assertEqual("value", mock.some_method())
149
150 # Mox
151 mock = mox.MockAnything()
152 mock.some_method().AndReturn("value")
153 mox.Replay(mock)
154 assertEqual("value", mock.some_method())
155 mox.Verify(mock)
156
157 # Mocker
158 mock = mocker.mock()
159 mock.some_method()
160 mocker.result("value")
161 mocker.replay()
162 assertEqual("value", mock.some_method())
163 mocker.verify()
164
165 ::
166
167 >>> # Dingus
168 >>> my_dingus = dingus.Dingus(some_method__returns="value")
169 >>> assertEqual("value", my_dingus.some_method())
170 >>> assert my_dingus.some_method.calls().once()
171
172 ::
173
174 >>> # fudge
175 >>> @fudge.test
176 ... def test():
177 ... my_fake = (fudge.Fake()
178 ... .expects('some_method')
179 ... .returns("value")
180 ... .times_called(1))
181 ...
182 >>> test()
183 Traceback (most recent call last):
184 ...
185 AssertionError: fake:my_fake.some_method() was not called
186
187
188 Creating partial mocks
189 ~~~~~~~~~~~~~~~~~~~~~~
190
191 .. doctest::
192
193 >>> # mock
194 >>> SomeObject.some_method = mock.Mock(return_value='value')
195 >>> assertEqual("value", SomeObject.some_method())
196
197 ::
198
199 # Flexmock
200 flexmock(SomeObject).should_receive("some_method").and_return('value')
201 assertEqual("value", mock.some_method())
202
203 # Mox
204 mock = mox.MockObject(SomeObject)
205 mock.some_method().AndReturn("value")
206 mox.Replay(mock)
207 assertEqual("value", mock.some_method())
208 mox.Verify(mock)
209
210 # Mocker
211 mock = mocker.mock(SomeObject)
212 mock.Get()
213 mocker.result("value")
214 mocker.replay()
215 assertEqual("value", mock.some_method())
216 mocker.verify()
217
218 ::
219
220 >>> # Dingus
221 >>> object = SomeObject
222 >>> object.some_method = dingus.Dingus(return_value="value")
223 >>> assertEqual("value", object.some_method())
224
225 ::
226
227 >>> # fudge
228 >>> fake = fudge.Fake().is_callable().returns("<fudge-value>")
229 >>> with fudge.patched_context(SomeObject, 'some_method', fake):
230 ... s = SomeObject()
231 ... assertEqual("<fudge-value>", s.some_method())
232 ...
233
234
235 Ensure calls are made in specific order
236 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237
238 .. doctest::
239
240 >>> # mock
241 >>> my_mock = mock.Mock(spec=SomeObject)
242 >>> my_mock.method1()
243 <Mock name='mock.method1()' id='...'>
244 >>> my_mock.method2()
245 <Mock name='mock.method2()' id='...'>
246 >>> assertEqual(my_mock.mock_calls, [call.method1(), call.method2()])
247
248 ::
249
250 # Flexmock
251 mock = flexmock(SomeObject)
252 mock.should_receive('method1').once.ordered.and_return('first thing')
253 mock.should_receive('method2').once.ordered.and_return('second thing')
254
255 # Mox
256 mock = mox.MockObject(SomeObject)
257 mock.method1().AndReturn('first thing')
258 mock.method2().AndReturn('second thing')
259 mox.Replay(mock)
260 mox.Verify(mock)
261
262 # Mocker
263 mock = mocker.mock()
264 with mocker.order():
265 mock.method1()
266 mocker.result('first thing')
267 mock.method2()
268 mocker.result('second thing')
269 mocker.replay()
270 mocker.verify()
271
272 ::
273
274 >>> # Dingus
275 >>> my_dingus = dingus.Dingus()
276 >>> my_dingus.method1()
277 <Dingus ...>
278 >>> my_dingus.method2()
279 <Dingus ...>
280 >>> assertEqual(['method1', 'method2'], [call.name for call in my_dingus.calls])
281
282 ::
283
284 >>> # fudge
285 >>> @fudge.test
286 ... def test():
287 ... my_fake = (fudge.Fake()
288 ... .remember_order()
289 ... .expects('method1')
290 ... .expects('method2'))
291 ... my_fake.method2()
292 ... my_fake.method1()
293 ...
294 >>> test()
295 Traceback (most recent call last):
296 ...
297 AssertionError: Call #1 was fake:my_fake.method2(); Expected: #1 fake:my_fake.method1(), #2 fake:my_fake.method2(), end
298
299
300 Raising exceptions
301 ~~~~~~~~~~~~~~~~~~
302
303 .. doctest::
304
305 >>> # mock
306 >>> my_mock = mock.Mock()
307 >>> my_mock.some_method.side_effect = SomeException("message")
308 >>> assertRaises(SomeException, my_mock.some_method)
309
310 ::
311
312 # Flexmock
313 mock = flexmock()
314 mock.should_receive("some_method").and_raise(SomeException("message"))
315 assertRaises(SomeException, mock.some_method)
316
317 # Mox
318 mock = mox.MockAnything()
319 mock.some_method().AndRaise(SomeException("message"))
320 mox.Replay(mock)
321 assertRaises(SomeException, mock.some_method)
322 mox.Verify(mock)
323
324 # Mocker
325 mock = mocker.mock()
326 mock.some_method()
327 mocker.throw(SomeException("message"))
328 mocker.replay()
329 assertRaises(SomeException, mock.some_method)
330 mocker.verify()
331
332 ::
333
334 >>> # Dingus
335 >>> my_dingus = dingus.Dingus()
336 >>> my_dingus.some_method = dingus.exception_raiser(SomeException)
337 >>> assertRaises(SomeException, my_dingus.some_method)
338
339 ::
340
341 >>> # fudge
342 >>> my_fake = (fudge.Fake()
343 ... .is_callable()
344 ... .raises(SomeException("message")))
345 ...
346 >>> my_fake()
347 Traceback (most recent call last):
348 ...
349 SomeException: message
350
351
352 Override new instances of a class
353 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
354
355 .. doctest::
356
357 >>> # mock
358 >>> with mock.patch('somemodule.Someclass') as MockClass:
359 ... MockClass.return_value = some_other_object
360 ... assertEqual(some_other_object, somemodule.Someclass())
361 ...
362
363
364 ::
365
366 # Flexmock
367 flexmock(some_module.SomeClass, new_instances=some_other_object)
368 assertEqual(some_other_object, some_module.SomeClass())
369
370 # Mox
371 # (you will probably have mox.Mox() available as self.mox in a real test)
372 mox.Mox().StubOutWithMock(some_module, 'SomeClass', use_mock_anything=True)
373 some_module.SomeClass().AndReturn(some_other_object)
374 mox.ReplayAll()
375 assertEqual(some_other_object, some_module.SomeClass())
376
377 # Mocker
378 instance = mocker.mock()
379 klass = mocker.replace(SomeClass, spec=None)
380 klass('expected', 'args')
381 mocker.result(instance)
382
383 ::
384
385 >>> # Dingus
386 >>> MockClass = dingus.Dingus(return_value=some_other_object)
387 >>> with dingus.patch('somemodule.SomeClass', MockClass):
388 ... assertEqual(some_other_object, somemodule.SomeClass())
389 ...
390
391 ::
392
393 >>> # fudge
394 >>> @fudge.patch('somemodule.SomeClass')
395 ... def test(FakeClass):
396 ... FakeClass.is_callable().returns(some_other_object)
397 ... assertEqual(some_other_object, somemodule.SomeClass())
398 ...
399 >>> test()
400
401
402 Call the same method multiple times
403 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
404
405 .. note::
406
407 You don't need to do *any* configuration to call `mock.Mock()` methods
408 multiple times. Attributes like `call_count`, `call_args_list` and
409 `method_calls` provide various different ways of making assertions about
410 how the mock was used.
411
412 .. doctest::
413
414 >>> # mock
415 >>> my_mock = mock.Mock()
416 >>> my_mock.some_method()
417 <Mock name='mock.some_method()' id='...'>
418 >>> my_mock.some_method()
419 <Mock name='mock.some_method()' id='...'>
420 >>> assert my_mock.some_method.call_count >= 2
421
422 ::
423
424 # Flexmock # (verifies that the method gets called at least twice)
425 flexmock(some_object).should_receive('some_method').at_least.twice
426
427 # Mox
428 # (does not support variable number of calls, so you need to create a new entry for each explicit call)
429 mock = mox.MockObject(some_object)
430 mock.some_method(mox.IgnoreArg(), mox.IgnoreArg())
431 mock.some_method(mox.IgnoreArg(), mox.IgnoreArg())
432 mox.Replay(mock)
433 mox.Verify(mock)
434
435 # Mocker
436 # (TODO)
437
438 ::
439
440 >>> # Dingus
441 >>> my_dingus = dingus.Dingus()
442 >>> my_dingus.some_method()
443 <Dingus ...>
444 >>> my_dingus.some_method()
445 <Dingus ...>
446 >>> assert len(my_dingus.calls('some_method')) == 2
447
448 ::
449
450 >>> # fudge
451 >>> @fudge.test
452 ... def test():
453 ... my_fake = fudge.Fake().expects('some_method').times_called(2)
454 ... my_fake.some_method()
455 ...
456 >>> test()
457 Traceback (most recent call last):
458 ...
459 AssertionError: fake:my_fake.some_method() was called 1 time(s). Expected 2.
460
461
462 Mock chained methods
463 ~~~~~~~~~~~~~~~~~~~~
464
465 .. doctest::
466
467 >>> # mock
468 >>> my_mock = mock.Mock()
469 >>> method3 = my_mock.method1.return_value.method2.return_value.method3
470 >>> method3.return_value = 'some value'
471 >>> assertEqual('some value', my_mock.method1().method2().method3(1, 2))
472 >>> method3.assert_called_once_with(1, 2)
473
474 ::
475
476 # Flexmock
477 # (intermediate method calls are automatically assigned to temporary fake objects
478 # and can be called with any arguments)
479 flexmock(some_object).should_receive(
480 'method1.method2.method3'
481 ).with_args(arg1, arg2).and_return('some value')
482 assertEqual('some_value', some_object.method1().method2().method3(arg1, arg2))
483
484 ::
485
486 # Mox
487 mock = mox.MockObject(some_object)
488 mock2 = mox.MockAnything()
489 mock3 = mox.MockAnything()
490 mock.method1().AndReturn(mock1)
491 mock2.method2().AndReturn(mock2)
492 mock3.method3(arg1, arg2).AndReturn('some_value')
493 self.mox.ReplayAll()
494 assertEqual("some_value", some_object.method1().method2().method3(arg1, arg2))
495 self.mox.VerifyAll()
496
497 # Mocker
498 # (TODO)
499
500 ::
501
502 >>> # Dingus
503 >>> my_dingus = dingus.Dingus()
504 >>> method3 = my_dingus.method1.return_value.method2.return_value.method3
505 >>> method3.return_value = 'some value'
506 >>> assertEqual('some value', my_dingus.method1().method2().method3(1, 2))
507 >>> assert method3.calls('()', 1, 2).once()
508
509 ::
510
511 >>> # fudge
512 >>> @fudge.test
513 ... def test():
514 ... my_fake = fudge.Fake()
515 ... (my_fake
516 ... .expects('method1')
517 ... .returns_fake()
518 ... .expects('method2')
519 ... .returns_fake()
520 ... .expects('method3')
521 ... .with_args(1, 2)
522 ... .returns('some value'))
523 ... assertEqual('some value', my_fake.method1().method2().method3(1, 2))
524 ...
525 >>> test()
526
527
528 Mocking a context manager
529 ~~~~~~~~~~~~~~~~~~~~~~~~~
530
531 Examples for mock, Dingus and fudge only (so far):
532
533 .. doctest::
534
535 >>> # mock
536 >>> my_mock = mock.MagicMock()
537 >>> with my_mock:
538 ... pass
539 ...
540 >>> my_mock.__enter__.assert_called_with()
541 >>> my_mock.__exit__.assert_called_with(None, None, None)
542
543 ::
544
545
546 >>> # Dingus (nothing special here; all dinguses are "magic mocks")
547 >>> my_dingus = dingus.Dingus()
548 >>> with my_dingus:
549 ... pass
550 ...
551 >>> assert my_dingus.__enter__.calls()
552 >>> assert my_dingus.__exit__.calls('()', None, None, None)
553
554 ::
555
556 >>> # fudge
557 >>> my_fake = fudge.Fake().provides('__enter__').provides('__exit__')
558 >>> with my_fake:
559 ... pass
560 ...
561
562
563 Mocking the builtin open used as a context manager
564 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
565
566 Example for mock only (so far):
567
568 .. doctest::
569
570 >>> # mock
571 >>> my_mock = mock.MagicMock()
572 >>> with mock.patch('__builtin__.open', my_mock):
573 ... manager = my_mock.return_value.__enter__.return_value
574 ... manager.read.return_value = 'some data'
575 ... with open('foo') as h:
576 ... data = h.read()
577 ...
578 >>> data
579 'some data'
580 >>> my_mock.assert_called_once_with('foo')
581
582 *or*:
583
584 .. doctest::
585
586 >>> # mock
587 >>> with mock.patch('__builtin__.open') as my_mock:
588 ... my_mock.return_value.__enter__ = lambda s: s
589 ... my_mock.return_value.__exit__ = mock.Mock()
590 ... my_mock.return_value.read.return_value = 'some data'
591 ... with open('foo') as h:
592 ... data = h.read()
593 ...
594 >>> data
595 'some data'
596 >>> my_mock.assert_called_once_with('foo')
597
598 ::
599
600 >>> # Dingus
601 >>> my_dingus = dingus.Dingus()
602 >>> with dingus.patch('__builtin__.open', my_dingus):
603 ... file_ = open.return_value.__enter__.return_value
604 ... file_.read.return_value = 'some data'
605 ... with open('foo') as h:
606 ... data = f.read()
607 ...
608 >>> data
609 'some data'
610 >>> assert my_dingus.calls('()', 'foo').once()
611
612 ::
613
614 >>> # fudge
615 >>> from contextlib import contextmanager
616 >>> from StringIO import StringIO
617 >>> @contextmanager
618 ... def fake_file(filename):
619 ... yield StringIO('sekrets')
620 ...
621 >>> with fudge.patch('__builtin__.open') as fake_open:
622 ... fake_open.is_callable().calls(fake_file)
623 ... with open('/etc/password') as f:
624 ... data = f.read()
625 ...
626 fake:__builtin__.open
627 >>> data
628 'sekrets'

mercurial