Python Unittest Examples: Mocking and Patching
Last updated:- Mock imported function
- Patch object of class
- Mocked method is called
- Patched function is called
- Mocked method is called with arguments
- Patched function is called with arguments
- Mock object method
- Mock object attribute
- Mock chained method calls
- Patch open file
- Get arguments passed to mocked method
- Mock vs Patch
TL;DR: See a working project with all examples on this github repo
Mock imported function
This is called patching.
Use patch("path.to.imported.function")
:
EXAMPLE:
Application code (main.py)
from myproject.helpers import complex_function # function_a is coupled to the output of complex_function def function_a(): return complex_function().upper()
Test code for
function_a()
from unittest.mock import patch from myproject.main import function_a def test_function_a(): # note that you must pass the name as it is imported on the application code with patch("myproject.main.complex_function") as complex_function_mock: # we dont care what the return value of the dependency is complex_function_mock.return_value = "foo" # we just want our function to work assert function_a() == "FOO"
Patch object of class
Use patch.object(MyClass, 'my_method', return_value="return value")
:
EXAMPLE:
application code:
class MyClass: def __init__(self, name): self.name = name def sayhi(self): return "hi my name is: {}".format(self.name) # instantiates MyClass and calls a method on the object def function_b(): param1 = MyClass("foo") # returns "hi my name is: foo" return param1.sayhi()
test code
from unittest.mock import patch def test_function_b(): # mock an object of class with patch.object(MyClass, 'sayhi', return_value="hi i'm a mock object"): # the MyClass object used within function_b will # be replaced by a mock defined in the # patch.object call above assert function_b() == "hi i'm a mock object"
Mocked method is called
Use
assert_not_called()
to assert a method was not called instead
To assert that a mocked method was called use assert_called()
EXAMPLE:
from unittest.mock import Mock
# this function takes an object as argument and calls a
# method on it
def function_with_call(some_obj, argument):
return some_obj.some_method(argument)
def test_called():
mock = Mock()
mock.some_method = Mock(return_value=None)
function_with_call(mock, "foo bar")
# will return true if method was called one or more times
mock.some_method.assert_called()
Patched function is called
Use of
assert_not_called()
to assert it was not called
Use patch(...)
and assert_called()
to assert that a pacthed function was called.
EXAMPLE:
Application code (main.py)
from myproject.helpers import complex_function def function_a(): return complex_function().upper()
Test code:
from unittest.mock import patch from myproject.main import function_a def test_called_patch(): with patch("myproject.main.complex_function") as patched_function: function_a() patched_function.assert_called()
Mocked method is called with arguments
Use assert_called_with(arg1, arg2, key1=kwarg1,key2=kwarg2,...)
to verify that the method was called using the arguments provided:
EXAMPLE:
from unittest.mock import Mock
def function_with_call(some_obj, argument):
return some_obj.some_method(argument)
def test_called():
mock = Mock()
mock.some_method = Mock(return_value=None)
function_with_call(mock, "foo bar")
# will return true if method was called one or more times
mock.some_method.assert_called_with("foo bar")
Patched function is called with arguments
Use patch(...)
and assert_called_with()
EXAMPLE:
application code (main.py)
from myproject.helpers import complex_function_with_params # this function takes both params, modifies them and send to # complex_function_with_params def function_e(param1, param2): return complex_function_with_params(param1.upper(), param2.upper())
test code
from unittest.mock import patch from myproject.main import function_e def test_called_with_patch(): with patch("myproject.main.complex_function_with_params") as patched_function: # function_e converts the params to upper case and # calls another function with those function_e("foo", "bar") patched_function.assert_called_with("FOO", "BAR")
Mock object method
Create a Mock()
object and assign another Mock object to the method name
EXAMPLE:
from unittest.mock import Mock
# function_c takes a parameter and calls .sayhi() on it
def function_c(param):
output = param.sayhi()
return output.upper()
def test_function_c():
mock_obj = Mock()
mock_obj.sayhi = Mock(return_value="foo")
# function_c takes as input a MyClass object, calls sayhi() on it
# and makes the result upper case
assert function_c(mock_obj) == "FOO"
Mock object attribute
Create a Mock()
object and assign stuff to attribute names:
EXAMPLE:
application code
# function_d takes a parameter and uses its .name attribute def function_d(param): output = param.name return output.upper()
test code
from unittest.mock import Mock def test_function_d(): mock_obj = Mock() mock_obj.name = "foo" assert function_d(mock_obj) == "FOO"
Mock chained method calls
The same can be done for patched objects
Use Mock
and assign to methods' return_value
:
EXAMPLE:
from unittest.mock import Mock
# this function calls a chain of methods on the given object
def my_function(some_object):
output = some_object.foo().bar.baz().quux()
return output.upper()
def test_chained():
mock_obj = Mock()
result_1 = mock_obj.foo.return_value
result_2 = result_1.bar.baz.return_value
result_2.quux.return_value = "hello world"
assert my_function(mock_obj) == "HELLO WORLD"
Patch open file
Lots more info on how to work with files here
Use patch()
with mock_open()
:
EXAMPLE:
application code (main.py)
# reads a file and converts the contents to upper case def file_contents_to_uppercase(path_to_file): with open(path_to_file, "r") as f: contents = f.read() return contents.upper()
test code
from unittest.mock import mock_open, patch from myproject.main import file_contents_to_uppercase def test_file_contents_to_upper_case(): # pass the desired content as parameter m = mock_open(read_data="foo bar") with patch('myproject.main.open', m): # it does not matter what file path you pass, # the file contents are mocked assert file_contents_to_uppercase("path/to/file") == "FOO BAR"
Get arguments passed to mocked method
Use mocked_method.call_args[0]
EXAMPLE:
from unittest.mock import Mock
def function_e(some_obj, argument):
return some_obj.some_method(argument)
def test_arguments():
mock = Mock() # mock object
mock.some_method = Mock(return_value=None) # mock method
function_e(mock, "foo bar")
mock.some_method.assert_called()
# arguments passed to method some_method
arguments_tuple = mock.some_method.call_args[0]
assert "foo bar" in arguments_tuple
Mock vs Patch
mock | patch |
---|---|
Used to replace something that is used in the current scope | Used to replace something that is imported and/or created in another scope |