This file contains various examples of how to mock and patch different objects/parameters in different ways.
The official documentation can be found here.
module.py
:
class Foo:
foo = 123
def __init__(self):
self.att = 123
@property
def bar(self):
return 123
def func(self):
return 123
test.py
:
import unittest
from unittest.mock import patch, Mock, PropertyMock
import module
class NewFoo:
foo = 456
class FooPatchAtt(module.Foo):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.att = 456
class TestFoo(unittest.TestCase):
def test_foo(self):
self.assertEqual(module.Foo.foo, 123)
self.assertEqual(module.Foo().att, 123)
self.assertEqual(module.Foo().bar, 123)
self.assertEqual(module.Foo().func(), 123)
@patch('module.Foo', new=NewFoo)
def test_patch_class_with_class(self):
self.assertEqual(module.Foo, NewFoo)
self.assertEqual(module.Foo.foo, 456)
@patch('module.Foo')
def test_patch_class_with_mock(self, mock_foo):
self.assertEqual(module.Foo, mock_foo)
module.Foo()
mock_foo.assert_called()
@patch('module.Foo.foo', new=456)
def test_patch_class_attribute(self):
self.assertEqual(module.Foo.foo, 456)
@patch('module.Foo', new=FooPatchAtt)
def test_patch_instance_attribute(self):
self.assertEqual(module.Foo().att, 456)
@patch('module.Foo.bar', new_callable=PropertyMock, return_value=456)
def test_patch_property(self, mock_bar):
self.assertEqual(module.Foo().bar, 456)
@patch('module.Foo.func', new=Mock(return_value=456))
def test_patch_function_with_mock(self):
self.assertEqual(module.Foo().func(), 456)
@patch('module.Foo.func', new=lambda *args, **kwargs: 456)
def test_patch_function_with_func(self):
self.assertEqual(module.Foo().func(), 456)
@patch('module.Foo.func', new=Mock(side_effect=ValueError)
def test_raise_exception(self):
with self.assertRaises(ValueError):
module.Foo().func()
@patch('module.Foo.func', new=Mock(side_effect=ValueError)
def test_does_not_raise_exception(self):
try:
module.Foo().func()
except Exception as e:
self.fail(f"module.Foo().func() unexpectedly raised an exception:\n{e}"
if __name__ == "__main__":
unittest.main()
As explained in the documentation section on autospeccing, if an attribute is defined solely in the __init__
function, then autospeccing cannot find it since it only sees attributes defined by the class.
Solutions to this include defining a default value for every attribute in the class scope, creating a new class which can be used for autospeccing, or patching the class with a new class which overwrites the attributes manually (this is what is done in the above example).