[TIP] Yet another Mock Library

Michael Foord fuzzyman at voidspace.org.uk
Mon Nov 19 13:56:06 PST 2007


Hello all,

Actually to call it a library is heavily overblown. It is a single Mock 
class in less than 50 lines of code. It does meet all of the major 
mocking patterns we use at Resolver.

The one major thing it doesn't do is handle the patching at a module / 
class level or patch out builtins (just another example of module level 
patching). Modules and classes are effectively globals - so any patching 
has to be undone which can make for annoying code to write.

I'm also not yet distributing the tests for mock.py - it currently uses 
some utilities from the Resolver test framework and I need permission to 
distribute these. Along with these are some decorators we use to 
simplify class / module patching which hopefully I will also be allowed 
to include.

Homepage: http://www.voidspace.org.uk/python/mock.html
Download: 
http://www.voidspace.org.uk/cgi-bin/voidspace/downman.py?section=python&file=mock.py

It is really a very simple class, intended for use with unittest or 
similar test frameworks. This is an advantage, over-mocking is a sign 
that you have too many dependencies in your code. :-)

Examples:

Mock objects can be used for:

    * Patching methods
    * Recording method calls on objects

 >>> from mock import Mock
 >>>
 >>> real = ProductionClass()
 >>> real.method = Mock()
 >>>
 >>> real.method(3, 4, 5, key='value')
 >>>
 >>> real.method.called
True
 >>> real.method.call_args
((3, 4, 5), {'key': 'value'})
 >>>
 >>> mock = Mock()
 >>> mock.something()
 >>> mock.method_calls
[('something', (), {})]
 >>>
 >>> mock = Mock(methods=['something'])
 >>> mock.something()
 >>> mock.something_else()
Traceback (most recent call last):
   ...
AttributeError: object has no attribute 'something_else'
Setting the return values on a mock object is trivially easy.way of 
looking at all method calls:

 >>> mock = Mock()
 >>> mock.return_value = 3
 >>> mock()
3

Of course you can do the same for methods on the mock:

 >>> mock = Mock()
 >>> mock.method.return_value = 3
 >>> mock.method()
3

If you need an attribute setting on your mock, just do it:
 >>> mock = Mock()
 >>> mock.x = 3
 >>> mock.x
3

Sometimes you want to mock up a more complex situation, like for example 
mock.connection.cursor().execute("SELECT 1"):

 >>> mock = Mock()
 >>> cursor = Mock()
 >>> mock.connection.cursor.return_value = cursor
 >>>
 >>> mock.connection.cursor().execute("SELECT 1")
 >>> mock.method_calls
[('connection.cursor', (), {})]
 >>> cursor.method_calls
[('execute', ('SELECT 1',), {})]
 >>>


All the best,


Michael
http://www.manning.com/foord



More information about the testing-in-python mailing list