[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