|  | ========================= | 
|  | Mock Library Comparison | 
|  | ========================= | 
|  |  | 
|  |  | 
|  | .. testsetup:: | 
|  |  | 
|  | def assertEqual(a, b): | 
|  | assert a == b, ("%r != %r" % (a, b)) | 
|  |  | 
|  | def assertRaises(Exc, func): | 
|  | try: | 
|  | func() | 
|  | except Exc: | 
|  | return | 
|  | assert False, ("%s not raised" % Exc) | 
|  |  | 
|  | sys.modules['somemodule'] = somemodule = mock.Mock(name='somemodule') | 
|  | class SomeException(Exception): | 
|  | some_method = method1 = method2 = None | 
|  | some_other_object = SomeObject = SomeException | 
|  |  | 
|  |  | 
|  | A side-by-side comparison of how to accomplish some basic tasks with mock and | 
|  | some other popular Python mocking libraries and frameworks. | 
|  |  | 
|  | These are: | 
|  |  | 
|  | * `flexmock <http://pypi.python.org/pypi/flexmock>`_ | 
|  | * `mox <http://pypi.python.org/pypi/mox>`_ | 
|  | * `Mocker <http://niemeyer.net/mocker>`_ | 
|  | * `dingus <http://pypi.python.org/pypi/dingus>`_ | 
|  | * `fudge <http://pypi.python.org/pypi/fudge>`_ | 
|  |  | 
|  | Popular python mocking frameworks not yet represented here include | 
|  | `MiniMock <http://pypi.python.org/pypi/MiniMock>`_. | 
|  |  | 
|  | `pMock <http://pmock.sourceforge.net/>`_ (last release 2004 and doesn't import | 
|  | in recent versions of Python) and | 
|  | `python-mock <http://python-mock.sourceforge.net/>`_ (last release 2005) are | 
|  | intentionally omitted. | 
|  |  | 
|  | .. note:: | 
|  |  | 
|  | A more up to date, and tested for all mock libraries (only the mock | 
|  | examples on this page can be executed as doctests) version of this | 
|  | comparison is maintained by Gary Bernhardt: | 
|  |  | 
|  | * `Python Mock Library Comparison | 
|  | <http://garybernhardt.github.com/python-mock-comparison/>`_ | 
|  |  | 
|  | This comparison is by no means complete, and also may not be fully idiomatic | 
|  | for all the libraries represented. *Please* contribute corrections, missing | 
|  | comparisons, or comparisons for additional libraries to the `mock issue | 
|  | tracker <https://code.google.com/p/mock/issues/list>`_. | 
|  |  | 
|  | This comparison page was originally created by the `Mox project | 
|  | <https://code.google.com/p/pymox/wiki/MoxComparison>`_ and then extended for | 
|  | `flexmock and mock <http://has207.github.com/flexmock/compare.html>`_ by | 
|  | Herman Sheremetyev. Dingus examples written by `Gary Bernhadt | 
|  | <http://garybernhardt.github.com/python-mock-comparison/>`_. fudge examples | 
|  | provided by `Kumar McMillan <http://farmdev.com/>`_. | 
|  |  | 
|  | .. note:: | 
|  |  | 
|  | The examples tasks here were originally created by Mox which is a mocking | 
|  | *framework* rather than a library like mock. The tasks shown naturally | 
|  | exemplify tasks that frameworks are good at and not the ones they make | 
|  | harder. In particular you can take a `Mock` or `MagicMock` object and use | 
|  | it in any way you want with no up-front configuration. The same is also | 
|  | true for Dingus. | 
|  |  | 
|  | The examples for mock here assume version 0.7.0. | 
|  |  | 
|  |  | 
|  | Simple fake object | 
|  | ~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.Mock() | 
|  | >>> my_mock.some_method.return_value = "calculated value" | 
|  | >>> my_mock.some_attribute = "value" | 
|  | >>> assertEqual("calculated value", my_mock.some_method()) | 
|  | >>> assertEqual("value", my_mock.some_attribute) | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | mock = flexmock(some_method=lambda: "calculated value", some_attribute="value") | 
|  | assertEqual("calculated value", mock.some_method()) | 
|  | assertEqual("value", mock.some_attribute) | 
|  |  | 
|  | # Mox | 
|  | mock = mox.MockAnything() | 
|  | mock.some_method().AndReturn("calculated value") | 
|  | mock.some_attribute = "value" | 
|  | mox.Replay(mock) | 
|  | assertEqual("calculated value", mock.some_method()) | 
|  | assertEqual("value", mock.some_attribute) | 
|  |  | 
|  | # Mocker | 
|  | mock = mocker.mock() | 
|  | mock.some_method() | 
|  | mocker.result("calculated value") | 
|  | mocker.replay() | 
|  | mock.some_attribute = "value" | 
|  | assertEqual("calculated value", mock.some_method()) | 
|  | assertEqual("value", mock.some_attribute) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus(some_attribute="value", | 
|  | ...                           some_method__returns="calculated value") | 
|  | >>> assertEqual("calculated value", my_dingus.some_method()) | 
|  | >>> assertEqual("value", my_dingus.some_attribute) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> my_fake = (fudge.Fake() | 
|  | ...            .provides('some_method') | 
|  | ...            .returns("calculated value") | 
|  | ...            .has_attr(some_attribute="value")) | 
|  | ... | 
|  | >>> assertEqual("calculated value", my_fake.some_method()) | 
|  | >>> assertEqual("value", my_fake.some_attribute) | 
|  |  | 
|  |  | 
|  | Simple mock | 
|  | ~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.Mock() | 
|  | >>> my_mock.some_method.return_value = "value" | 
|  | >>> assertEqual("value", my_mock.some_method()) | 
|  | >>> my_mock.some_method.assert_called_once_with() | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | mock = flexmock() | 
|  | mock.should_receive("some_method").and_return("value").once | 
|  | assertEqual("value", mock.some_method()) | 
|  |  | 
|  | # Mox | 
|  | mock = mox.MockAnything() | 
|  | mock.some_method().AndReturn("value") | 
|  | mox.Replay(mock) | 
|  | assertEqual("value", mock.some_method()) | 
|  | mox.Verify(mock) | 
|  |  | 
|  | # Mocker | 
|  | mock = mocker.mock() | 
|  | mock.some_method() | 
|  | mocker.result("value") | 
|  | mocker.replay() | 
|  | assertEqual("value", mock.some_method()) | 
|  | mocker.verify() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus(some_method__returns="value") | 
|  | >>> assertEqual("value", my_dingus.some_method()) | 
|  | >>> assert my_dingus.some_method.calls().once() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> @fudge.test | 
|  | ... def test(): | 
|  | ...     my_fake = (fudge.Fake() | 
|  | ...                .expects('some_method') | 
|  | ...                .returns("value") | 
|  | ...                .times_called(1)) | 
|  | ... | 
|  | >>> test() | 
|  | Traceback (most recent call last): | 
|  | ... | 
|  | AssertionError: fake:my_fake.some_method() was not called | 
|  |  | 
|  |  | 
|  | Creating partial mocks | 
|  | ~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> SomeObject.some_method = mock.Mock(return_value='value') | 
|  | >>> assertEqual("value", SomeObject.some_method()) | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | flexmock(SomeObject).should_receive("some_method").and_return('value') | 
|  | assertEqual("value", mock.some_method()) | 
|  |  | 
|  | # Mox | 
|  | mock = mox.MockObject(SomeObject) | 
|  | mock.some_method().AndReturn("value") | 
|  | mox.Replay(mock) | 
|  | assertEqual("value", mock.some_method()) | 
|  | mox.Verify(mock) | 
|  |  | 
|  | # Mocker | 
|  | mock = mocker.mock(SomeObject) | 
|  | mock.Get() | 
|  | mocker.result("value") | 
|  | mocker.replay() | 
|  | assertEqual("value", mock.some_method()) | 
|  | mocker.verify() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> object = SomeObject | 
|  | >>> object.some_method = dingus.Dingus(return_value="value") | 
|  | >>> assertEqual("value", object.some_method()) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> fake = fudge.Fake().is_callable().returns("<fudge-value>") | 
|  | >>> with fudge.patched_context(SomeObject, 'some_method', fake): | 
|  | ...     s = SomeObject() | 
|  | ...     assertEqual("<fudge-value>", s.some_method()) | 
|  | ... | 
|  |  | 
|  |  | 
|  | Ensure calls are made in specific order | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.Mock(spec=SomeObject) | 
|  | >>> my_mock.method1() | 
|  | <Mock name='mock.method1()' id='...'> | 
|  | >>> my_mock.method2() | 
|  | <Mock name='mock.method2()' id='...'> | 
|  | >>> assertEqual(my_mock.mock_calls, [call.method1(), call.method2()]) | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | mock = flexmock(SomeObject) | 
|  | mock.should_receive('method1').once.ordered.and_return('first thing') | 
|  | mock.should_receive('method2').once.ordered.and_return('second thing') | 
|  |  | 
|  | # Mox | 
|  | mock = mox.MockObject(SomeObject) | 
|  | mock.method1().AndReturn('first thing') | 
|  | mock.method2().AndReturn('second thing') | 
|  | mox.Replay(mock) | 
|  | mox.Verify(mock) | 
|  |  | 
|  | # Mocker | 
|  | mock = mocker.mock() | 
|  | with mocker.order(): | 
|  | mock.method1() | 
|  | mocker.result('first thing') | 
|  | mock.method2() | 
|  | mocker.result('second thing') | 
|  | mocker.replay() | 
|  | mocker.verify() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus() | 
|  | >>> my_dingus.method1() | 
|  | <Dingus ...> | 
|  | >>> my_dingus.method2() | 
|  | <Dingus ...> | 
|  | >>> assertEqual(['method1', 'method2'], [call.name for call in my_dingus.calls]) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> @fudge.test | 
|  | ... def test(): | 
|  | ...     my_fake = (fudge.Fake() | 
|  | ...                .remember_order() | 
|  | ...                .expects('method1') | 
|  | ...                .expects('method2')) | 
|  | ...     my_fake.method2() | 
|  | ...     my_fake.method1() | 
|  | ... | 
|  | >>> test() | 
|  | Traceback (most recent call last): | 
|  | ... | 
|  | AssertionError: Call #1 was fake:my_fake.method2(); Expected: #1 fake:my_fake.method1(), #2 fake:my_fake.method2(), end | 
|  |  | 
|  |  | 
|  | Raising exceptions | 
|  | ~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.Mock() | 
|  | >>> my_mock.some_method.side_effect = SomeException("message") | 
|  | >>> assertRaises(SomeException, my_mock.some_method) | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | mock = flexmock() | 
|  | mock.should_receive("some_method").and_raise(SomeException("message")) | 
|  | assertRaises(SomeException, mock.some_method) | 
|  |  | 
|  | # Mox | 
|  | mock = mox.MockAnything() | 
|  | mock.some_method().AndRaise(SomeException("message")) | 
|  | mox.Replay(mock) | 
|  | assertRaises(SomeException, mock.some_method) | 
|  | mox.Verify(mock) | 
|  |  | 
|  | # Mocker | 
|  | mock = mocker.mock() | 
|  | mock.some_method() | 
|  | mocker.throw(SomeException("message")) | 
|  | mocker.replay() | 
|  | assertRaises(SomeException, mock.some_method) | 
|  | mocker.verify() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus() | 
|  | >>> my_dingus.some_method = dingus.exception_raiser(SomeException) | 
|  | >>> assertRaises(SomeException, my_dingus.some_method) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> my_fake = (fudge.Fake() | 
|  | ...            .is_callable() | 
|  | ...            .raises(SomeException("message"))) | 
|  | ... | 
|  | >>> my_fake() | 
|  | Traceback (most recent call last): | 
|  | ... | 
|  | SomeException: message | 
|  |  | 
|  |  | 
|  | Override new instances of a class | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> with mock.patch('somemodule.Someclass') as MockClass: | 
|  | ...     MockClass.return_value = some_other_object | 
|  | ...     assertEqual(some_other_object, somemodule.Someclass()) | 
|  | ... | 
|  |  | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | flexmock(some_module.SomeClass, new_instances=some_other_object) | 
|  | assertEqual(some_other_object, some_module.SomeClass()) | 
|  |  | 
|  | # Mox | 
|  | # (you will probably have mox.Mox() available as self.mox in a real test) | 
|  | mox.Mox().StubOutWithMock(some_module, 'SomeClass', use_mock_anything=True) | 
|  | some_module.SomeClass().AndReturn(some_other_object) | 
|  | mox.ReplayAll() | 
|  | assertEqual(some_other_object, some_module.SomeClass()) | 
|  |  | 
|  | # Mocker | 
|  | instance = mocker.mock() | 
|  | klass = mocker.replace(SomeClass, spec=None) | 
|  | klass('expected', 'args') | 
|  | mocker.result(instance) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> MockClass = dingus.Dingus(return_value=some_other_object) | 
|  | >>> with dingus.patch('somemodule.SomeClass', MockClass): | 
|  | ...     assertEqual(some_other_object, somemodule.SomeClass()) | 
|  | ... | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> @fudge.patch('somemodule.SomeClass') | 
|  | ... def test(FakeClass): | 
|  | ...     FakeClass.is_callable().returns(some_other_object) | 
|  | ...     assertEqual(some_other_object, somemodule.SomeClass()) | 
|  | ... | 
|  | >>> test() | 
|  |  | 
|  |  | 
|  | Call the same method multiple times | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. note:: | 
|  |  | 
|  | You don't need to do *any* configuration to call `mock.Mock()` methods | 
|  | multiple times. Attributes like `call_count`, `call_args_list` and | 
|  | `method_calls` provide various different ways of making assertions about | 
|  | how the mock was used. | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.Mock() | 
|  | >>> my_mock.some_method() | 
|  | <Mock name='mock.some_method()' id='...'> | 
|  | >>> my_mock.some_method() | 
|  | <Mock name='mock.some_method()' id='...'> | 
|  | >>> assert my_mock.some_method.call_count >= 2 | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock # (verifies that the method gets called at least twice) | 
|  | flexmock(some_object).should_receive('some_method').at_least.twice | 
|  |  | 
|  | # Mox | 
|  | # (does not support variable number of calls, so you need to create a new entry for each explicit call) | 
|  | mock = mox.MockObject(some_object) | 
|  | mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) | 
|  | mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) | 
|  | mox.Replay(mock) | 
|  | mox.Verify(mock) | 
|  |  | 
|  | # Mocker | 
|  | # (TODO) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus() | 
|  | >>> my_dingus.some_method() | 
|  | <Dingus ...> | 
|  | >>> my_dingus.some_method() | 
|  | <Dingus ...> | 
|  | >>> assert len(my_dingus.calls('some_method')) == 2 | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> @fudge.test | 
|  | ... def test(): | 
|  | ...     my_fake = fudge.Fake().expects('some_method').times_called(2) | 
|  | ...     my_fake.some_method() | 
|  | ... | 
|  | >>> test() | 
|  | Traceback (most recent call last): | 
|  | ... | 
|  | AssertionError: fake:my_fake.some_method() was called 1 time(s). Expected 2. | 
|  |  | 
|  |  | 
|  | Mock chained methods | 
|  | ~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.Mock() | 
|  | >>> method3 = my_mock.method1.return_value.method2.return_value.method3 | 
|  | >>> method3.return_value = 'some value' | 
|  | >>> assertEqual('some value', my_mock.method1().method2().method3(1, 2)) | 
|  | >>> method3.assert_called_once_with(1, 2) | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Flexmock | 
|  | # (intermediate method calls are automatically assigned to temporary fake objects | 
|  | # and can be called with any arguments) | 
|  | flexmock(some_object).should_receive( | 
|  | 'method1.method2.method3' | 
|  | ).with_args(arg1, arg2).and_return('some value') | 
|  | assertEqual('some_value', some_object.method1().method2().method3(arg1, arg2)) | 
|  |  | 
|  | :: | 
|  |  | 
|  | # Mox | 
|  | mock = mox.MockObject(some_object) | 
|  | mock2 = mox.MockAnything() | 
|  | mock3 = mox.MockAnything() | 
|  | mock.method1().AndReturn(mock1) | 
|  | mock2.method2().AndReturn(mock2) | 
|  | mock3.method3(arg1, arg2).AndReturn('some_value') | 
|  | self.mox.ReplayAll() | 
|  | assertEqual("some_value", some_object.method1().method2().method3(arg1, arg2)) | 
|  | self.mox.VerifyAll() | 
|  |  | 
|  | # Mocker | 
|  | # (TODO) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus() | 
|  | >>> method3 = my_dingus.method1.return_value.method2.return_value.method3 | 
|  | >>> method3.return_value = 'some value' | 
|  | >>> assertEqual('some value', my_dingus.method1().method2().method3(1, 2)) | 
|  | >>> assert method3.calls('()', 1, 2).once() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> @fudge.test | 
|  | ... def test(): | 
|  | ...     my_fake = fudge.Fake() | 
|  | ...     (my_fake | 
|  | ...      .expects('method1') | 
|  | ...      .returns_fake() | 
|  | ...      .expects('method2') | 
|  | ...      .returns_fake() | 
|  | ...      .expects('method3') | 
|  | ...      .with_args(1, 2) | 
|  | ...      .returns('some value')) | 
|  | ...     assertEqual('some value', my_fake.method1().method2().method3(1, 2)) | 
|  | ... | 
|  | >>> test() | 
|  |  | 
|  |  | 
|  | Mocking a context manager | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | Examples for mock, Dingus and fudge only (so far): | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.MagicMock() | 
|  | >>> with my_mock: | 
|  | ...     pass | 
|  | ... | 
|  | >>> my_mock.__enter__.assert_called_with() | 
|  | >>> my_mock.__exit__.assert_called_with(None, None, None) | 
|  |  | 
|  | :: | 
|  |  | 
|  |  | 
|  | >>> # Dingus (nothing special here; all dinguses are "magic mocks") | 
|  | >>> my_dingus = dingus.Dingus() | 
|  | >>> with my_dingus: | 
|  | ...     pass | 
|  | ... | 
|  | >>> assert my_dingus.__enter__.calls() | 
|  | >>> assert my_dingus.__exit__.calls('()', None, None, None) | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> my_fake = fudge.Fake().provides('__enter__').provides('__exit__') | 
|  | >>> with my_fake: | 
|  | ...     pass | 
|  | ... | 
|  |  | 
|  |  | 
|  | Mocking the builtin open used as a context manager | 
|  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
|  |  | 
|  | Example for mock only (so far): | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> my_mock = mock.MagicMock() | 
|  | >>> with mock.patch('__builtin__.open', my_mock): | 
|  | ...     manager = my_mock.return_value.__enter__.return_value | 
|  | ...     manager.read.return_value = 'some data' | 
|  | ...     with open('foo') as h: | 
|  | ...         data = h.read() | 
|  | ... | 
|  | >>> data | 
|  | 'some data' | 
|  | >>> my_mock.assert_called_once_with('foo') | 
|  |  | 
|  | *or*: | 
|  |  | 
|  | .. doctest:: | 
|  |  | 
|  | >>> # mock | 
|  | >>> with mock.patch('__builtin__.open') as my_mock: | 
|  | ...     my_mock.return_value.__enter__ = lambda s: s | 
|  | ...     my_mock.return_value.__exit__ = mock.Mock() | 
|  | ...     my_mock.return_value.read.return_value = 'some data' | 
|  | ...     with open('foo') as h: | 
|  | ...         data = h.read() | 
|  | ... | 
|  | >>> data | 
|  | 'some data' | 
|  | >>> my_mock.assert_called_once_with('foo') | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # Dingus | 
|  | >>> my_dingus = dingus.Dingus() | 
|  | >>> with dingus.patch('__builtin__.open', my_dingus): | 
|  | ...     file_ = open.return_value.__enter__.return_value | 
|  | ...     file_.read.return_value = 'some data' | 
|  | ...     with open('foo') as h: | 
|  | ...         data = f.read() | 
|  | ... | 
|  | >>> data | 
|  | 'some data' | 
|  | >>> assert my_dingus.calls('()', 'foo').once() | 
|  |  | 
|  | :: | 
|  |  | 
|  | >>> # fudge | 
|  | >>> from contextlib import contextmanager | 
|  | >>> from StringIO import StringIO | 
|  | >>> @contextmanager | 
|  | ... def fake_file(filename): | 
|  | ...     yield StringIO('sekrets') | 
|  | ... | 
|  | >>> with fudge.patch('__builtin__.open') as fake_open: | 
|  | ...     fake_open.is_callable().calls(fake_file) | 
|  | ...     with open('/etc/password') as f: | 
|  | ...         data = f.read() | 
|  | ... | 
|  | fake:__builtin__.open | 
|  | >>> data | 
|  | 'sekrets' |