1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/python/mock-1.0.0/docs/compare.txt Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,628 @@ 1.4 +========================= 1.5 + Mock Library Comparison 1.6 +========================= 1.7 + 1.8 + 1.9 +.. testsetup:: 1.10 + 1.11 + def assertEqual(a, b): 1.12 + assert a == b, ("%r != %r" % (a, b)) 1.13 + 1.14 + def assertRaises(Exc, func): 1.15 + try: 1.16 + func() 1.17 + except Exc: 1.18 + return 1.19 + assert False, ("%s not raised" % Exc) 1.20 + 1.21 + sys.modules['somemodule'] = somemodule = mock.Mock(name='somemodule') 1.22 + class SomeException(Exception): 1.23 + some_method = method1 = method2 = None 1.24 + some_other_object = SomeObject = SomeException 1.25 + 1.26 + 1.27 +A side-by-side comparison of how to accomplish some basic tasks with mock and 1.28 +some other popular Python mocking libraries and frameworks. 1.29 + 1.30 +These are: 1.31 + 1.32 +* `flexmock <http://pypi.python.org/pypi/flexmock>`_ 1.33 +* `mox <http://pypi.python.org/pypi/mox>`_ 1.34 +* `Mocker <http://niemeyer.net/mocker>`_ 1.35 +* `dingus <http://pypi.python.org/pypi/dingus>`_ 1.36 +* `fudge <http://pypi.python.org/pypi/fudge>`_ 1.37 + 1.38 +Popular python mocking frameworks not yet represented here include 1.39 +`MiniMock <http://pypi.python.org/pypi/MiniMock>`_. 1.40 + 1.41 +`pMock <http://pmock.sourceforge.net/>`_ (last release 2004 and doesn't import 1.42 +in recent versions of Python) and 1.43 +`python-mock <http://python-mock.sourceforge.net/>`_ (last release 2005) are 1.44 +intentionally omitted. 1.45 + 1.46 +.. note:: 1.47 + 1.48 + A more up to date, and tested for all mock libraries (only the mock 1.49 + examples on this page can be executed as doctests) version of this 1.50 + comparison is maintained by Gary Bernhardt: 1.51 + 1.52 + * `Python Mock Library Comparison 1.53 + <http://garybernhardt.github.com/python-mock-comparison/>`_ 1.54 + 1.55 +This comparison is by no means complete, and also may not be fully idiomatic 1.56 +for all the libraries represented. *Please* contribute corrections, missing 1.57 +comparisons, or comparisons for additional libraries to the `mock issue 1.58 +tracker <https://code.google.com/p/mock/issues/list>`_. 1.59 + 1.60 +This comparison page was originally created by the `Mox project 1.61 +<https://code.google.com/p/pymox/wiki/MoxComparison>`_ and then extended for 1.62 +`flexmock and mock <http://has207.github.com/flexmock/compare.html>`_ by 1.63 +Herman Sheremetyev. Dingus examples written by `Gary Bernhadt 1.64 +<http://garybernhardt.github.com/python-mock-comparison/>`_. fudge examples 1.65 +provided by `Kumar McMillan <http://farmdev.com/>`_. 1.66 + 1.67 +.. note:: 1.68 + 1.69 + The examples tasks here were originally created by Mox which is a mocking 1.70 + *framework* rather than a library like mock. The tasks shown naturally 1.71 + exemplify tasks that frameworks are good at and not the ones they make 1.72 + harder. In particular you can take a `Mock` or `MagicMock` object and use 1.73 + it in any way you want with no up-front configuration. The same is also 1.74 + true for Dingus. 1.75 + 1.76 + The examples for mock here assume version 0.7.0. 1.77 + 1.78 + 1.79 +Simple fake object 1.80 +~~~~~~~~~~~~~~~~~~ 1.81 + 1.82 +.. doctest:: 1.83 + 1.84 + >>> # mock 1.85 + >>> my_mock = mock.Mock() 1.86 + >>> my_mock.some_method.return_value = "calculated value" 1.87 + >>> my_mock.some_attribute = "value" 1.88 + >>> assertEqual("calculated value", my_mock.some_method()) 1.89 + >>> assertEqual("value", my_mock.some_attribute) 1.90 + 1.91 +:: 1.92 + 1.93 + # Flexmock 1.94 + mock = flexmock(some_method=lambda: "calculated value", some_attribute="value") 1.95 + assertEqual("calculated value", mock.some_method()) 1.96 + assertEqual("value", mock.some_attribute) 1.97 + 1.98 + # Mox 1.99 + mock = mox.MockAnything() 1.100 + mock.some_method().AndReturn("calculated value") 1.101 + mock.some_attribute = "value" 1.102 + mox.Replay(mock) 1.103 + assertEqual("calculated value", mock.some_method()) 1.104 + assertEqual("value", mock.some_attribute) 1.105 + 1.106 + # Mocker 1.107 + mock = mocker.mock() 1.108 + mock.some_method() 1.109 + mocker.result("calculated value") 1.110 + mocker.replay() 1.111 + mock.some_attribute = "value" 1.112 + assertEqual("calculated value", mock.some_method()) 1.113 + assertEqual("value", mock.some_attribute) 1.114 + 1.115 +:: 1.116 + 1.117 + >>> # Dingus 1.118 + >>> my_dingus = dingus.Dingus(some_attribute="value", 1.119 + ... some_method__returns="calculated value") 1.120 + >>> assertEqual("calculated value", my_dingus.some_method()) 1.121 + >>> assertEqual("value", my_dingus.some_attribute) 1.122 + 1.123 +:: 1.124 + 1.125 + >>> # fudge 1.126 + >>> my_fake = (fudge.Fake() 1.127 + ... .provides('some_method') 1.128 + ... .returns("calculated value") 1.129 + ... .has_attr(some_attribute="value")) 1.130 + ... 1.131 + >>> assertEqual("calculated value", my_fake.some_method()) 1.132 + >>> assertEqual("value", my_fake.some_attribute) 1.133 + 1.134 + 1.135 +Simple mock 1.136 +~~~~~~~~~~~ 1.137 + 1.138 +.. doctest:: 1.139 + 1.140 + >>> # mock 1.141 + >>> my_mock = mock.Mock() 1.142 + >>> my_mock.some_method.return_value = "value" 1.143 + >>> assertEqual("value", my_mock.some_method()) 1.144 + >>> my_mock.some_method.assert_called_once_with() 1.145 + 1.146 +:: 1.147 + 1.148 + # Flexmock 1.149 + mock = flexmock() 1.150 + mock.should_receive("some_method").and_return("value").once 1.151 + assertEqual("value", mock.some_method()) 1.152 + 1.153 + # Mox 1.154 + mock = mox.MockAnything() 1.155 + mock.some_method().AndReturn("value") 1.156 + mox.Replay(mock) 1.157 + assertEqual("value", mock.some_method()) 1.158 + mox.Verify(mock) 1.159 + 1.160 + # Mocker 1.161 + mock = mocker.mock() 1.162 + mock.some_method() 1.163 + mocker.result("value") 1.164 + mocker.replay() 1.165 + assertEqual("value", mock.some_method()) 1.166 + mocker.verify() 1.167 + 1.168 +:: 1.169 + 1.170 + >>> # Dingus 1.171 + >>> my_dingus = dingus.Dingus(some_method__returns="value") 1.172 + >>> assertEqual("value", my_dingus.some_method()) 1.173 + >>> assert my_dingus.some_method.calls().once() 1.174 + 1.175 +:: 1.176 + 1.177 + >>> # fudge 1.178 + >>> @fudge.test 1.179 + ... def test(): 1.180 + ... my_fake = (fudge.Fake() 1.181 + ... .expects('some_method') 1.182 + ... .returns("value") 1.183 + ... .times_called(1)) 1.184 + ... 1.185 + >>> test() 1.186 + Traceback (most recent call last): 1.187 + ... 1.188 + AssertionError: fake:my_fake.some_method() was not called 1.189 + 1.190 + 1.191 +Creating partial mocks 1.192 +~~~~~~~~~~~~~~~~~~~~~~ 1.193 + 1.194 +.. doctest:: 1.195 + 1.196 + >>> # mock 1.197 + >>> SomeObject.some_method = mock.Mock(return_value='value') 1.198 + >>> assertEqual("value", SomeObject.some_method()) 1.199 + 1.200 +:: 1.201 + 1.202 + # Flexmock 1.203 + flexmock(SomeObject).should_receive("some_method").and_return('value') 1.204 + assertEqual("value", mock.some_method()) 1.205 + 1.206 + # Mox 1.207 + mock = mox.MockObject(SomeObject) 1.208 + mock.some_method().AndReturn("value") 1.209 + mox.Replay(mock) 1.210 + assertEqual("value", mock.some_method()) 1.211 + mox.Verify(mock) 1.212 + 1.213 + # Mocker 1.214 + mock = mocker.mock(SomeObject) 1.215 + mock.Get() 1.216 + mocker.result("value") 1.217 + mocker.replay() 1.218 + assertEqual("value", mock.some_method()) 1.219 + mocker.verify() 1.220 + 1.221 +:: 1.222 + 1.223 + >>> # Dingus 1.224 + >>> object = SomeObject 1.225 + >>> object.some_method = dingus.Dingus(return_value="value") 1.226 + >>> assertEqual("value", object.some_method()) 1.227 + 1.228 +:: 1.229 + 1.230 + >>> # fudge 1.231 + >>> fake = fudge.Fake().is_callable().returns("<fudge-value>") 1.232 + >>> with fudge.patched_context(SomeObject, 'some_method', fake): 1.233 + ... s = SomeObject() 1.234 + ... assertEqual("<fudge-value>", s.some_method()) 1.235 + ... 1.236 + 1.237 + 1.238 +Ensure calls are made in specific order 1.239 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.240 + 1.241 +.. doctest:: 1.242 + 1.243 + >>> # mock 1.244 + >>> my_mock = mock.Mock(spec=SomeObject) 1.245 + >>> my_mock.method1() 1.246 + <Mock name='mock.method1()' id='...'> 1.247 + >>> my_mock.method2() 1.248 + <Mock name='mock.method2()' id='...'> 1.249 + >>> assertEqual(my_mock.mock_calls, [call.method1(), call.method2()]) 1.250 + 1.251 +:: 1.252 + 1.253 + # Flexmock 1.254 + mock = flexmock(SomeObject) 1.255 + mock.should_receive('method1').once.ordered.and_return('first thing') 1.256 + mock.should_receive('method2').once.ordered.and_return('second thing') 1.257 + 1.258 + # Mox 1.259 + mock = mox.MockObject(SomeObject) 1.260 + mock.method1().AndReturn('first thing') 1.261 + mock.method2().AndReturn('second thing') 1.262 + mox.Replay(mock) 1.263 + mox.Verify(mock) 1.264 + 1.265 + # Mocker 1.266 + mock = mocker.mock() 1.267 + with mocker.order(): 1.268 + mock.method1() 1.269 + mocker.result('first thing') 1.270 + mock.method2() 1.271 + mocker.result('second thing') 1.272 + mocker.replay() 1.273 + mocker.verify() 1.274 + 1.275 +:: 1.276 + 1.277 + >>> # Dingus 1.278 + >>> my_dingus = dingus.Dingus() 1.279 + >>> my_dingus.method1() 1.280 + <Dingus ...> 1.281 + >>> my_dingus.method2() 1.282 + <Dingus ...> 1.283 + >>> assertEqual(['method1', 'method2'], [call.name for call in my_dingus.calls]) 1.284 + 1.285 +:: 1.286 + 1.287 + >>> # fudge 1.288 + >>> @fudge.test 1.289 + ... def test(): 1.290 + ... my_fake = (fudge.Fake() 1.291 + ... .remember_order() 1.292 + ... .expects('method1') 1.293 + ... .expects('method2')) 1.294 + ... my_fake.method2() 1.295 + ... my_fake.method1() 1.296 + ... 1.297 + >>> test() 1.298 + Traceback (most recent call last): 1.299 + ... 1.300 + AssertionError: Call #1 was fake:my_fake.method2(); Expected: #1 fake:my_fake.method1(), #2 fake:my_fake.method2(), end 1.301 + 1.302 + 1.303 +Raising exceptions 1.304 +~~~~~~~~~~~~~~~~~~ 1.305 + 1.306 +.. doctest:: 1.307 + 1.308 + >>> # mock 1.309 + >>> my_mock = mock.Mock() 1.310 + >>> my_mock.some_method.side_effect = SomeException("message") 1.311 + >>> assertRaises(SomeException, my_mock.some_method) 1.312 + 1.313 +:: 1.314 + 1.315 + # Flexmock 1.316 + mock = flexmock() 1.317 + mock.should_receive("some_method").and_raise(SomeException("message")) 1.318 + assertRaises(SomeException, mock.some_method) 1.319 + 1.320 + # Mox 1.321 + mock = mox.MockAnything() 1.322 + mock.some_method().AndRaise(SomeException("message")) 1.323 + mox.Replay(mock) 1.324 + assertRaises(SomeException, mock.some_method) 1.325 + mox.Verify(mock) 1.326 + 1.327 + # Mocker 1.328 + mock = mocker.mock() 1.329 + mock.some_method() 1.330 + mocker.throw(SomeException("message")) 1.331 + mocker.replay() 1.332 + assertRaises(SomeException, mock.some_method) 1.333 + mocker.verify() 1.334 + 1.335 +:: 1.336 + 1.337 + >>> # Dingus 1.338 + >>> my_dingus = dingus.Dingus() 1.339 + >>> my_dingus.some_method = dingus.exception_raiser(SomeException) 1.340 + >>> assertRaises(SomeException, my_dingus.some_method) 1.341 + 1.342 +:: 1.343 + 1.344 + >>> # fudge 1.345 + >>> my_fake = (fudge.Fake() 1.346 + ... .is_callable() 1.347 + ... .raises(SomeException("message"))) 1.348 + ... 1.349 + >>> my_fake() 1.350 + Traceback (most recent call last): 1.351 + ... 1.352 + SomeException: message 1.353 + 1.354 + 1.355 +Override new instances of a class 1.356 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.357 + 1.358 +.. doctest:: 1.359 + 1.360 + >>> # mock 1.361 + >>> with mock.patch('somemodule.Someclass') as MockClass: 1.362 + ... MockClass.return_value = some_other_object 1.363 + ... assertEqual(some_other_object, somemodule.Someclass()) 1.364 + ... 1.365 + 1.366 + 1.367 +:: 1.368 + 1.369 + # Flexmock 1.370 + flexmock(some_module.SomeClass, new_instances=some_other_object) 1.371 + assertEqual(some_other_object, some_module.SomeClass()) 1.372 + 1.373 + # Mox 1.374 + # (you will probably have mox.Mox() available as self.mox in a real test) 1.375 + mox.Mox().StubOutWithMock(some_module, 'SomeClass', use_mock_anything=True) 1.376 + some_module.SomeClass().AndReturn(some_other_object) 1.377 + mox.ReplayAll() 1.378 + assertEqual(some_other_object, some_module.SomeClass()) 1.379 + 1.380 + # Mocker 1.381 + instance = mocker.mock() 1.382 + klass = mocker.replace(SomeClass, spec=None) 1.383 + klass('expected', 'args') 1.384 + mocker.result(instance) 1.385 + 1.386 +:: 1.387 + 1.388 + >>> # Dingus 1.389 + >>> MockClass = dingus.Dingus(return_value=some_other_object) 1.390 + >>> with dingus.patch('somemodule.SomeClass', MockClass): 1.391 + ... assertEqual(some_other_object, somemodule.SomeClass()) 1.392 + ... 1.393 + 1.394 +:: 1.395 + 1.396 + >>> # fudge 1.397 + >>> @fudge.patch('somemodule.SomeClass') 1.398 + ... def test(FakeClass): 1.399 + ... FakeClass.is_callable().returns(some_other_object) 1.400 + ... assertEqual(some_other_object, somemodule.SomeClass()) 1.401 + ... 1.402 + >>> test() 1.403 + 1.404 + 1.405 +Call the same method multiple times 1.406 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.407 + 1.408 +.. note:: 1.409 + 1.410 + You don't need to do *any* configuration to call `mock.Mock()` methods 1.411 + multiple times. Attributes like `call_count`, `call_args_list` and 1.412 + `method_calls` provide various different ways of making assertions about 1.413 + how the mock was used. 1.414 + 1.415 +.. doctest:: 1.416 + 1.417 + >>> # mock 1.418 + >>> my_mock = mock.Mock() 1.419 + >>> my_mock.some_method() 1.420 + <Mock name='mock.some_method()' id='...'> 1.421 + >>> my_mock.some_method() 1.422 + <Mock name='mock.some_method()' id='...'> 1.423 + >>> assert my_mock.some_method.call_count >= 2 1.424 + 1.425 +:: 1.426 + 1.427 + # Flexmock # (verifies that the method gets called at least twice) 1.428 + flexmock(some_object).should_receive('some_method').at_least.twice 1.429 + 1.430 + # Mox 1.431 + # (does not support variable number of calls, so you need to create a new entry for each explicit call) 1.432 + mock = mox.MockObject(some_object) 1.433 + mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) 1.434 + mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) 1.435 + mox.Replay(mock) 1.436 + mox.Verify(mock) 1.437 + 1.438 + # Mocker 1.439 + # (TODO) 1.440 + 1.441 +:: 1.442 + 1.443 + >>> # Dingus 1.444 + >>> my_dingus = dingus.Dingus() 1.445 + >>> my_dingus.some_method() 1.446 + <Dingus ...> 1.447 + >>> my_dingus.some_method() 1.448 + <Dingus ...> 1.449 + >>> assert len(my_dingus.calls('some_method')) == 2 1.450 + 1.451 +:: 1.452 + 1.453 + >>> # fudge 1.454 + >>> @fudge.test 1.455 + ... def test(): 1.456 + ... my_fake = fudge.Fake().expects('some_method').times_called(2) 1.457 + ... my_fake.some_method() 1.458 + ... 1.459 + >>> test() 1.460 + Traceback (most recent call last): 1.461 + ... 1.462 + AssertionError: fake:my_fake.some_method() was called 1 time(s). Expected 2. 1.463 + 1.464 + 1.465 +Mock chained methods 1.466 +~~~~~~~~~~~~~~~~~~~~ 1.467 + 1.468 +.. doctest:: 1.469 + 1.470 + >>> # mock 1.471 + >>> my_mock = mock.Mock() 1.472 + >>> method3 = my_mock.method1.return_value.method2.return_value.method3 1.473 + >>> method3.return_value = 'some value' 1.474 + >>> assertEqual('some value', my_mock.method1().method2().method3(1, 2)) 1.475 + >>> method3.assert_called_once_with(1, 2) 1.476 + 1.477 +:: 1.478 + 1.479 + # Flexmock 1.480 + # (intermediate method calls are automatically assigned to temporary fake objects 1.481 + # and can be called with any arguments) 1.482 + flexmock(some_object).should_receive( 1.483 + 'method1.method2.method3' 1.484 + ).with_args(arg1, arg2).and_return('some value') 1.485 + assertEqual('some_value', some_object.method1().method2().method3(arg1, arg2)) 1.486 + 1.487 +:: 1.488 + 1.489 + # Mox 1.490 + mock = mox.MockObject(some_object) 1.491 + mock2 = mox.MockAnything() 1.492 + mock3 = mox.MockAnything() 1.493 + mock.method1().AndReturn(mock1) 1.494 + mock2.method2().AndReturn(mock2) 1.495 + mock3.method3(arg1, arg2).AndReturn('some_value') 1.496 + self.mox.ReplayAll() 1.497 + assertEqual("some_value", some_object.method1().method2().method3(arg1, arg2)) 1.498 + self.mox.VerifyAll() 1.499 + 1.500 + # Mocker 1.501 + # (TODO) 1.502 + 1.503 +:: 1.504 + 1.505 + >>> # Dingus 1.506 + >>> my_dingus = dingus.Dingus() 1.507 + >>> method3 = my_dingus.method1.return_value.method2.return_value.method3 1.508 + >>> method3.return_value = 'some value' 1.509 + >>> assertEqual('some value', my_dingus.method1().method2().method3(1, 2)) 1.510 + >>> assert method3.calls('()', 1, 2).once() 1.511 + 1.512 +:: 1.513 + 1.514 + >>> # fudge 1.515 + >>> @fudge.test 1.516 + ... def test(): 1.517 + ... my_fake = fudge.Fake() 1.518 + ... (my_fake 1.519 + ... .expects('method1') 1.520 + ... .returns_fake() 1.521 + ... .expects('method2') 1.522 + ... .returns_fake() 1.523 + ... .expects('method3') 1.524 + ... .with_args(1, 2) 1.525 + ... .returns('some value')) 1.526 + ... assertEqual('some value', my_fake.method1().method2().method3(1, 2)) 1.527 + ... 1.528 + >>> test() 1.529 + 1.530 + 1.531 +Mocking a context manager 1.532 +~~~~~~~~~~~~~~~~~~~~~~~~~ 1.533 + 1.534 +Examples for mock, Dingus and fudge only (so far): 1.535 + 1.536 +.. doctest:: 1.537 + 1.538 + >>> # mock 1.539 + >>> my_mock = mock.MagicMock() 1.540 + >>> with my_mock: 1.541 + ... pass 1.542 + ... 1.543 + >>> my_mock.__enter__.assert_called_with() 1.544 + >>> my_mock.__exit__.assert_called_with(None, None, None) 1.545 + 1.546 +:: 1.547 + 1.548 + 1.549 + >>> # Dingus (nothing special here; all dinguses are "magic mocks") 1.550 + >>> my_dingus = dingus.Dingus() 1.551 + >>> with my_dingus: 1.552 + ... pass 1.553 + ... 1.554 + >>> assert my_dingus.__enter__.calls() 1.555 + >>> assert my_dingus.__exit__.calls('()', None, None, None) 1.556 + 1.557 +:: 1.558 + 1.559 + >>> # fudge 1.560 + >>> my_fake = fudge.Fake().provides('__enter__').provides('__exit__') 1.561 + >>> with my_fake: 1.562 + ... pass 1.563 + ... 1.564 + 1.565 + 1.566 +Mocking the builtin open used as a context manager 1.567 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.568 + 1.569 +Example for mock only (so far): 1.570 + 1.571 +.. doctest:: 1.572 + 1.573 + >>> # mock 1.574 + >>> my_mock = mock.MagicMock() 1.575 + >>> with mock.patch('__builtin__.open', my_mock): 1.576 + ... manager = my_mock.return_value.__enter__.return_value 1.577 + ... manager.read.return_value = 'some data' 1.578 + ... with open('foo') as h: 1.579 + ... data = h.read() 1.580 + ... 1.581 + >>> data 1.582 + 'some data' 1.583 + >>> my_mock.assert_called_once_with('foo') 1.584 + 1.585 +*or*: 1.586 + 1.587 +.. doctest:: 1.588 + 1.589 + >>> # mock 1.590 + >>> with mock.patch('__builtin__.open') as my_mock: 1.591 + ... my_mock.return_value.__enter__ = lambda s: s 1.592 + ... my_mock.return_value.__exit__ = mock.Mock() 1.593 + ... my_mock.return_value.read.return_value = 'some data' 1.594 + ... with open('foo') as h: 1.595 + ... data = h.read() 1.596 + ... 1.597 + >>> data 1.598 + 'some data' 1.599 + >>> my_mock.assert_called_once_with('foo') 1.600 + 1.601 +:: 1.602 + 1.603 + >>> # Dingus 1.604 + >>> my_dingus = dingus.Dingus() 1.605 + >>> with dingus.patch('__builtin__.open', my_dingus): 1.606 + ... file_ = open.return_value.__enter__.return_value 1.607 + ... file_.read.return_value = 'some data' 1.608 + ... with open('foo') as h: 1.609 + ... data = f.read() 1.610 + ... 1.611 + >>> data 1.612 + 'some data' 1.613 + >>> assert my_dingus.calls('()', 'foo').once() 1.614 + 1.615 +:: 1.616 + 1.617 + >>> # fudge 1.618 + >>> from contextlib import contextmanager 1.619 + >>> from StringIO import StringIO 1.620 + >>> @contextmanager 1.621 + ... def fake_file(filename): 1.622 + ... yield StringIO('sekrets') 1.623 + ... 1.624 + >>> with fudge.patch('__builtin__.open') as fake_open: 1.625 + ... fake_open.is_callable().calls(fake_file) 1.626 + ... with open('/etc/password') as f: 1.627 + ... data = f.read() 1.628 + ... 1.629 + fake:__builtin__.open 1.630 + >>> data 1.631 + 'sekrets' 1.632 \ No newline at end of file