[TIP] [python] Mocking and patching a class with mock.py?

Michael Foord fuzzyman at voidspace.org.uk
Mon Jan 21 05:06:11 PST 2008

Daryl Spitzer wrote:
> Thanks Michael.  I get it now.  I went with just setting the mock's
> return value to itself.  It might be a little more confusing to the
> uninitiated, but I think one can get used to that idiom quickly.  (And
> I don't feel the need to use two mocks in this case.)
> So the working code looks like:
> -----
>     mock = Mock(spec=doessomething.MyClass)
>     mock.return_value = mock # so MyClass() returns a mock instance
>     @patch('doessomething', 'MyClass', mock)
>     def test_does_something(self):
>         doessomething.does_something()
>         self.assertEqual(TestDoessomething.mock.do_something.call_args_list,
>                          [(('x',), {})])
> -----
> Though I find myself using this pattern instead:
> -----
>     def test_does_something(self):
>         mock = Mock(spec=doessomething.MyClass)
>         mock.return_value = mock
>         @apply
>         @patch('doessomething', 'MyClass', mock)
>         def do_test():
>             doessomething.does_something()
>             self.assertEqual(mock.do_something.call_args_list,
>                              [(('x',), {})])
> -----
> As the number of tests grows, it seems safer to define the mocks
> inside the test methods, even if I do then have to have an internal
> function in order to use the patch decorator.
> I'd love to read anyone's suggestions for improvement though.

It looks fine. Personally I prefer to keep one test per test method and 
minimise inner functions, but its not always possible. We're not using 
'spec' at Resolver, but you can check that your objects are being used 
correctly by changing your last assert to:

self.assertEqual(mock.method_calls, [('do_something', ('x',), {})])

This will fail if any additional methods get called, and then you can 
use the two argument form of the 'patch' decorator (meaning you don't 
have to instantiate the mock yourself and reducing test code).

All the best,

Michael Foord

More information about the testing-in-python mailing list