[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