[TIP] Flexmock 0.7.3 released

Michael Foord fuzzyman at voidspace.org.uk
Thu Feb 24 14:10:50 PST 2011


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
>

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




More information about the testing-in-python mailing list