pythonunit-testingmocking

Mocking a class: Mock() or patch()?


I am using mock with Python and was wondering which of those two approaches is better (read: more pythonic).

Method one: Just create a mock object and use that. The code looks like:

def test_one (self):
    mock = Mock()
    mock.method.return_value = True 
    
    # This should call mock.method and check the result. 
    self.sut.something(mock) 

    self.assertTrue(mock.method.called)

Method two: Use patch to create a mock. The code looks like:

@patch("MyClass")
def test_two (self, mock):
    instance = mock.return_value
    instance.method.return_value = True
    
    # This should call mock.method and check the result.
    self.sut.something(instance) 

    self.assertTrue(instance.method.called)

Both methods do the same thing. I am unsure of the differences.

Could anyone enlighten me?


Solution

  • mock.patch is a very very different critter than mock.Mock. patch replaces the class with a mock object and lets you work with the mock instance. Take a look at this snippet:

    >>> class MyClass(object):
    ...   def __init__(self):
    ...     print 'Created MyClass@{0}'.format(id(self))
    ... 
    >>> def create_instance():
    ...   return MyClass()
    ... 
    >>> x = create_instance()
    Created MyClass@4299548304
    >>> 
    >>> @mock.patch('__main__.MyClass')
    ... def create_instance2(MyClass):
    ...   MyClass.return_value = 'foo'
    ...   return create_instance()
    ... 
    >>> i = create_instance2()
    >>> i
    'foo'
    >>> def create_instance():
    ...   print MyClass
    ...   return MyClass()
    ...
    >>> create_instance2()
    <mock.Mock object at 0x100505d90>
    'foo'
    >>> create_instance()
    <class '__main__.MyClass'>
    Created MyClass@4300234128
    <__main__.MyClass object at 0x100505d90>
    

    patch replaces MyClass in a way that allows you to control the usage of the class in functions that you call. Once you patch a class, references to the class are completely replaced by the mock instance.

    mock.patch is usually used when you are testing something that creates a new instance of a class inside of the test. mock.Mock instances are clearer and are preferred. If your self.sut.something method created an instance of MyClass instead of receiving an instance as a parameter, then mock.patch would be appropriate here.