[TIP] mock library comparisons (was Re: Flexmock 0.7.3 released)

Kumar McMillan kumar.mcmillan at gmail.com
Sun Feb 27 11:36:47 PST 2011


On Sun, Feb 27, 2011 at 12:30 PM, Michael Foord
<fuzzyman at voidspace.org.uk> wrote:
> On 27/02/2011 18:08, Herman Sheremetyev wrote:
>>
>> Ah cool, good timing :) I just finished adding your suggestions to my
>> own version. I haven't gotten around to doing the context manager bit,
>> but I should be able to whip up at least the flexmock and mox versions
>> for that later this week.
>
> Cool, ping me when they're done and if you make any other changes to the
> flexmock examples it would be great if you could point them out to me.
>
>
>> I was also thinking we should maybe start a thread here and get the
>> authors or enthusiasts of the other mock libraries to submit their own
>> versions for the stuff that I was missing.
>
> We can hope. :-)
>
> Kumar - fudge examples?

Sure, when I can find the time I'll submit the fudge code.  Fudge will
look nearly identical to flexmock though since both are based on the
same Ruby counterpart.

>
> All the best,
>
> Michael
>>
>> Cheers,
>>
>> -Herman
>>
>> On Mon, Feb 28, 2011 at 2:49 AM, Michael Foord
>> <fuzzyman at voidspace.org.uk>  wrote:
>>>
>>> On 24/02/2011 22:10, Michael Foord wrote:
>>>>
>>>> On 24/02/2011 17:11, Herman Sheremetyev wrote:
>>>>>
>>>>> On Fri, Feb 25, 2011 at 12:48 AM, Michael Foord
>>>>> <fuzzyman at voidspace.org.uk>    wrote:
>>>>>>
>>>>>> [snip...]
>>>>>> If anyone else writes a comparison I'll be very happy to criticise
>>>>>> (uh... I
>>>>>> mean improve) their examples of using mock. :-)
>>>>>
>>>>> I put up a few Mock examples. Comments welcome!
>>>>>
>>>>> http://has207.github.com/flexmock/compare.html
>>>>>
>>> Hey Herman,
>>>
>>> I thought this was such a good idea I've added it to the mock 0.7.0
>>> documentation:
>>>
>>>    http://www.voidspace.org.uk/python/mock/compare.html
>>>
>>> (With credits to you and the Mox project for the original comparisons.)
>>>
>>> Feel free to send me any updates. Authors or users of other mock
>>> libraries
>>> please also send in corrections / comparisons.
>>>
>>> In this version the mock examples are all in their own "block". This
>>> *isn't*
>>> to highlight them specially, but its because I've made them all doctests
>>> so
>>> I can ensure they are kept up to date.
>>>
>>> The source for this page is available in the mock repo, or online at:
>>>
>>>    http://www.voidspace.org.uk/python/mock/_sources/compare.txt
>>>
>>> All the best,
>>>
>>> Michael Foord
>>>
>>>> Pretty good. A few minor suggestions and filling in the missing ones
>>>> (all
>>>> assuming mock 0.7.0):
>>>>
>>>> Simple Mock
>>>> Make the last line: my_mock.some_method.assert_called_once_with()
>>>>
>>>> Creating Partial Mocks
>>>> I *think* what you want (instead of using patch) is:
>>>>
>>>> mock = mock.Mock(spec=SomeObject)
>>>>
>>>> Ensure calls are made in a specific order:
>>>>
>>>> mock = mock.Mock(spec=SomeObject)
>>>> #mock.method1.return_value = 'first thing' # entirely optional
>>>> #mock.method2.return_value = 'second thing'
>>>>
>>>> mock.method1()
>>>> mock.method2()
>>>>
>>>> assert mock.method_calls == [
>>>>    ('method1',)
>>>>    ('method2',)
>>>> ]
>>>>
>>>> Raising exceptions (a minor change):
>>>>
>>>> my_mock.some_method.side_effect = SomeException("message")
>>>>
>>>>
>>>> Override new instances of a class:
>>>>
>>>> with mock.patch('somemodule.Someclass') as MockClass:
>>>>    MockClass.return_value = some_other_object
>>>>    assert some_other_object == some_module.SomeClass()
>>>>
>>>> (alternatively use patch.object(somemodule, 'SomeClass') to patch on the
>>>> module as an object instead of by name)
>>>>
>>>> You can also use patch as a decorator instead of a context manager:
>>>>
>>>> @patch('somemodule.Someclass')
>>>> def my_test_function(MockClass):
>>>>    MockClass.return_value = some_other_object
>>>>    assert some_other_object == some_module.SomeClass()
>>>>
>>>> Call the same method multiple times
>>>>
>>>> mock = Mock()
>>>> mock.some_method()
>>>> mock.some_method()
>>>>
>>>> assert mock.some_method.call_count>= 2
>>>>
>>>> (A lot of information about the calls is available, depending on exactly
>>>> what information you want. You don't need to do *anything* to merely
>>>> *allow*
>>>> multiple calls though.)
>>>>
>>>>
>>>> Mock chained methods
>>>>
>>>> my_mock = mock.Mock()
>>>> # if you don't need 'some value' you can leave the default return value
>>>> in
>>>> place
>>>> # and assert on equality / identity rather than by value
>>>> my_mock.method1.return_value.method2.return_value.method3.return_value =
>>>> 'some value'
>>>>
>>>> assert 'some_value' == my_mock.method1().method2().method3(arg1, arg2)
>>>>
>>>> method3 = my_mock.method1.return_value.method2.return_value.method3
>>>> method3. assert_called_once_with(arg1, arg2)
>>>>
>>>> These look prettier if you keep around references to the intermediate
>>>> mocks rather than chaining it all on one line, but you can do it.
>>>>
>>>>
>>>> How about adding an example of mocking a context manager:
>>>>
>>>> my_mock = mock.MagicMock()
>>>>
>>>> with my_mock:
>>>>    pass
>>>>
>>>> my_mock.__enter__.assert_called_with()
>>>> my_mock.__exit__.assert_called_with(None, None, None)
>>>>
>>>> Or even mocking out "open" when used as a context manager:
>>>>
>>>> First way:
>>>>
>>>>>>> my_mock = MagicMock()
>>>>>>> with 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')
>>>>
>>>> Second way:
>>>>
>>>>>>> with patch('__builtin__.open') as mock:
>>>>
>>>> ...     mock.return_value.__enter__ = lambda s: s
>>>> ...     mock.return_value.__exit__ = Mock()
>>>> ...     mock.return_value.read.return_value = 'some data'
>>>> ...     with open('foo') as h:
>>>> ...         data = h.read()
>>>> ...
>>>>>>>
>>>>>>> data
>>>>
>>>> 'some data'
>>>>>>>
>>>>>>> mock.assert_called_once_with('foo')
>>>>
>>>>> Cheers,
>>>>>
>>>>> -Herman
>>>>
>>>
>>> --
>>> http://www.voidspace.org.uk/
>>>
>>> May you do good and not evil
>>> May you find forgiveness for yourself and forgive others
>>> May you share freely, never taking more than you give.
>>> -- the sqlite blessing http://www.sqlite.org/different.html
>>>
>>>
>
>
> --
> http://www.voidspace.org.uk/
>
> May you do good and not evil
> May you find forgiveness for yourself and forgive others
> May you share freely, never taking more than you give.
> -- the sqlite blessing http://www.sqlite.org/different.html
>
>



More information about the testing-in-python mailing list