Introduction
This article provides a detailed introduction to the use of patch
in Python's unittest.
patch
Python's unittest patch()
method creates a mock object and swaps references to the specified patch destination object. The main arguments are as follows.
Argument | Description |
---|---|
target |
The object to patch. Specify the module name in string format or specify the object itself. |
new |
The object to replace target with. Optional. |
side_effect |
Function that defines the exception to be raised when the mock is called, the value to be returned, or the callable object. Optional. |
return_value |
Value returned when a mock is called. Optional. |
autospec |
If True , ensures that the new object correctly meets the specifications of the target object. |
spec |
If True , ensures that the new object correctly meets the specifications of the target object. |
create |
A boolean value specifying whether to automatically create attributes for mock calls. Optional, defaults to False . |
new_callable |
If new is not a callable object, specify a callable object to create a callable object. |
unsafe |
If the patching target is a module, a value of False will cause the verification to be performed. Optional; default is True . |
new
The new
argument to the patch
method can be used to completely replace the original object. This argument can be used to create a complete new object as a mock object. The following is an example of replacing a Foo
object using the new
argument.
from unittest.mock import patch
class Foo:
def bar(self):
return "original"
with patch('__main__.Foo', new=lambda: "mock"):
f = Foo()
assert f.bar() == "mock"
In this example, a call to the bar()
method on an instance of the Foo
class returns "mock"
. That is, the original object is replaced by a mock object.
It is also possible to set a dummy value to a global variable.
from unittest.mock import patch
def test_my_global_variable():
with patch('my_module.my_global_variable', new='dummy'):
assert my_module.my_global_variable == 'dummy'
In this example, my_module.my_global_variable
is replaced with the string 'dummy'
. The new
argument sets the given new value for the global variable.
return_value
The return_value
argument can be used to specify the value to be returned when the mock is called. The following example creates a mock that returns the value specified by return_value
when my_function
is called.
from unittest.mock import patch
def my_function():
return 42
with patch('__main__.my_function', return_value=84):
result = my_function()
print(result) # 84
wraps
The wraps
argument allows a mock to mimic the behavior of the object it wraps. That is, the mock will have the attributes and methods of the object it wraps. The following example creates a mock that performs the original my_function
when my_function
is called.
from unittest.mock import patch
def my_function():
return 42
with patch('__main__.my_function', wraps=my_function):
result = my_function()
print(result) # 42
side_effect
The side_effect
argument can be used to specify an exception to be raised when the mock is called. The following example creates a mock that raises a ValueError
when my_function
is called.
from unittest.mock import patch
def my_function():
return 42
with patch('__main__.my_function', side_effect=ValueError('oops')):
result = my_function()
print(result) # ValueError: oops
patch.object
patch.object()
is a method of unittest.mock
used to replace the attributes of a given object with a mock object. This method can be used to replace the attributes of any object in the module, such as class instance attributes or global variables. This allows you to configure the test to run in a particular state.
The syntax of patch.object()
is as follows.
patch.object(target, attribute, new=DEFAULT, **kwargs)
Argument | Description |
---|---|
target |
Specify the object to be patched. |
attribute |
Specify the name of the attribute to be patched. |
new |
Specify a new value for the object. The default value is DEFAULT , which automatically creates a mock object. |
**kwargs |
Used to specify additional patching arguments. |
The following is an example of using patch.object()
.
from unittest.mock import patch
class MyClass:
def __init__(self):
self.x = 10
def my_function():
obj = MyClass()
return obj.x
with patch.object(MyClass, 'x', 20):
assert my_function() == 20
In this example, the instance attribute x
of MyClass
is patched and set to 20
. Since my_function()
creates an instance of MyClass
and returns x
, the return value of my_function()
is 20
.
Other examples of patch.object
include
- Replace a method of an object
from unittest.mock import patch
class MyClass:
def my_method(self):
return "original"
with patch.object(MyClass, "my_method", return_value="mocked"):
obj = MyClass()
result = obj.my_method()
print(result) # => "mocked"
- Replace module attribute
from unittest.mock import patch
import my_module
with patch.object(my_module, "my_function", return_value="mocked"):
result = my_module.my_function()
print(result) # => "mocked"
- Raise an Exception
from unittest.mock import patch
def my_function():
raise ValueError("original")
with patch.object(__main__, "my_function", side_effect=RuntimeError("mocked")):
with pytest.raises(RuntimeError, match="mocked"):
my_function()
Difference from patch
Both patch
and patch.object
are methods of unittest.mock
to create and configure a mock, but there are differences in usage.
patch
takes a string path or object as an argument that specifies the object to be mocked. If the object to be mocked is a class method, it will mock the class name in the string passed as the first argument and replace it with the mock object. Also, patch
is intended to be used within a with
statement.
On the other hand, patch.object
takes an object to be mocked and a string that specifies the attributes of the object as arguments. Even if the object to be mocked is a class method, the object passed as the first argument is itself mocked and used to replace its attributes. patch.object
need not be used within a with
statement.
Thus, you can use patch.object
to mock only certain attributes of an object, but you can use patch
to mock the entire object.
For example, suppose you have the following code.
class MyClass:
def my_method(self):
return 'real'
my_instance = MyClass()
You can mock an entire MyClass
using patch
as follows
from unittest.mock import patch
with patch('my_module.MyClass') as MockClass:
instance = MockClass.return_value
instance.my_method.return_value = 'mocked'
assert my_instance.my_method() == 'mocked'
On the other hand, you can mock only the my_method
attribute of MyClass
using patch.object
as follows.
from unittest.mock import patch
with patch.object(my_instance, 'my_method') as mock_method:
mock_method.return_value = 'mocked'
assert my_instance.my_method() == 'mocked'
Decorators and with statements
In Python's unittest patch
, using decorators and with
statements has essentially the same effect, but there are differences in the way they are written.
When using decorators, you can enable mocking for all test methods in a test case. The following is an example of using decorators.
import unittest
from unittest.mock import patch
class MyTestCase(unittest.TestCase):
@patch('mymodule.some_function')
def test_my_function(self, mock_some_function):
# test ode with mocked function
If you use the with
statement, you can enable mocking only within the with
statement. The following is an example of using the with
statement.
import unittest
from unittest.mock import patch
class MyTestCase(unittest.TestCase):
def test_my_function(self):
with patch('mymodule.some_function') as mock_some_function:
# test code with mocked function
In general, using decorators keeps the code concise. However, if you need to customize the mock for each test method, you can use a with
statement. Also, when using the with
statement, the mock is automatically cleaned up at the end of the with
block, so if something fails during testing, the cleanup will still occur.
Define multiple patches
An example of defining multiple patches is shown below.
For example, suppose you have the following module.
import os
def my_function():
return os.path.abspath(__file__)
To define multiple patches for this module, do the following.
import unittest.mock
import my_module
class TestMyModule(unittest.TestCase):
def test_my_function(self):
with unittest.mock.patch('my_module.os'):
with unittest.mock.patch('my_module.os.path.abspath') as abspath_mock:
abspath_mock.return_value = 'my/absolute/path'
result = my_module.my_function()
self.assertEqual(result, 'my/absolute/path')
In this example, the patch is applied to the os
module and its path.abspath
function. To apply a patch, use the unittest.mock.patch()
method, with the path of the object to which you want to apply the patch as an argument. To apply multiple patches, use nested with
statements. Patch objects can also be aliased using the as
clause. Here we have an alias of abspath_mock
and use the return_value
attribute to set the return value of the mock.
To define multiple patch
decorators, use the following.
from unittest.mock import patch
@patch('module1.function1')
@patch('module2.function2')
def test_my_function(mock_function2, mock_function1):
# test code
pass
In this example, two patch
decorators are used to patch module1.function1
and module2.function2
. In this case, care should be taken to ensure that the order of the test function arguments matches the order of the decorators. That is, mock_function1
is a mock of module1.function1
and mock_function2
is a mock of module2.function2
.
References