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