Last updated: Apr 11, 2024
Reading timeยท3 min
Set the side_effect
attribute of the Mock
object to a list containing the
values to mock multiple return values in a Python unit test.
When the side_effect
attribute is set to an iterable, each call to the mock
returns the next value in the iterable.
from unittest.mock import Mock m = Mock() m.side_effect = ['bobby', 'hadz', 'com'] print(m()) # ๐๏ธ bobby print(m()) # ๐๏ธ hadz print(m()) # ๐๏ธ com
If you need to return multiple values from a Python Mock (e.g. a list), set the
return_value
attribute to a list.
from unittest.mock import Mock m = Mock() m.return_value = ['bobby', 'hadz', 'com'] print(m()) # ๐๏ธ ['bobby', 'hadz', 'com'] print(m()) # ๐๏ธ ['bobby', 'hadz', 'com'] print(m()) # ๐๏ธ ['bobby', 'hadz', 'com']
We used the
unittest.mock.Mock()
class to create a new Mock
object.
The side_effect attribute can be set to an iterable, a function to be called when the mock is called or an exception to be raised.
We set the side_effect
attribute to a list containing 3 items we want to
return from the Mock()
.
from unittest.mock import Mock m = Mock() m.side_effect = ['bobby', 'hadz', 'com'] print(m()) # ๐๏ธ bobby print(m()) # ๐๏ธ hadz print(m()) # ๐๏ธ com
When side_effect
is set to an iterable, each call to the Mock
returns the
next value in the iterable.
You can also pass the return values list to the Mock
class upon instantiation.
from unittest.mock import Mock # ๐๏ธ passing side_effect list upon instantiation m = Mock(side_effect=['bobby', 'hadz', 'com']) print(m()) # ๐๏ธ bobby print(m()) # ๐๏ธ hadz print(m()) # ๐๏ธ com
The code sample achieves the same result.
You can also supply the side_effect
argument when instantiating the
MagicMock()
class.
from unittest.mock import MagicMock m = MagicMock(side_effect=['bobby', 'hadz', 'com']) print(m()) # ๐๏ธ bobby print(m()) # ๐๏ธ hadz print(m()) # ๐๏ธ com
The MagicMock
class is a subclass of Mock
with default implementations for
most magic methods.
When you use the MagicMock
class, you don't have to configure the magic
methods yourself.
If you exhaust the iterator, a StopIteration
error is raised.
from unittest.mock import Mock m = Mock() m.side_effect = ['bobby', 'hadz', 'com'] print(m()) # ๐๏ธ bobby print(m()) # ๐๏ธ hadz print(m()) # ๐๏ธ com # โ๏ธ StopIteration print(m())
You can use the itertools
built-in module if you want to return a specific
value after the iterator has been exhausted instead of raising a StopIteration
error.
from unittest.mock import Mock import itertools m = Mock() m.side_effect = itertools.chain( ['bobby', 'hadz'], itertools.repeat('com') ) print(m()) # ๐๏ธ bobby print(m()) # ๐๏ธ hadz print(m()) # ๐๏ธ com print(m()) # ๐๏ธ com print(m()) # ๐๏ธ com print(m()) # ๐๏ธ com
Instead of raising a StopIteration
error, we return the string "com"
after
the iterator is exhausted.
You can also use the patch() function decorator to return multiple values from a Mock.
Suppose we have the following example.py
file.
def greet(name): return f'hello {name}'
Here is an example of mocking the example.greet
function with multiple return
values.
from unittest.mock import patch import example @patch('example.greet', side_effect=['hello Alice', 'hello Bobby', 'hello Carl']) def test_greet_function(greet_patched): assert example.greet('Alice') == 'hello Alice' assert example.greet('Bobby') == 'hello Bobby' assert example.greet('Carl') == 'hello Carl' print(greet_patched) print(greet_patched.called) assert greet_patched is example.greet assert greet_patched.called assert greet_patched.call_count == 3 test_greet_function()
We used the patch()
function decorator to patch the greet
function from the
example
module.
The first argument the patch()
function takes should be a string in the form
of package.module.functionName
or package.module.ClassName
.
The target must be importable from the environment in which you are calling
patch()
.
We passed the side_effect
sequence of return values to the @patch()
function.
@patch('example.greet', side_effect=['hello Alice', 'hello Bobby', 'hello Carl'])
Calls to the example.greet()
method will return the items from the sequence
one after the other.
@patch('example.greet', side_effect=['hello Alice', 'hello Bobby', 'hello Carl']) def test_greet_function(greet_patched): assert example.greet('Alice') == 'hello Alice' assert example.greet('Bobby') == 'hello Bobby' assert example.greet('Carl') == 'hello Carl'
The decorated function gets passed the mock object.
You can assert that the mock has been called, how many times it has been called, etc.
print(greet_patched) print(greet_patched.called) assert greet_patched is example.greet assert greet_patched.called assert greet_patched.call_count == 3
Here is an example of asserting that the mock was called with specific arguments.
from unittest.mock import patch import example @patch('example.greet', side_effect=['hello Alice', 'hello Bobby', 'hello Carl']) def test_greet_function(greet_patched): assert example.greet('Alice') == 'hello Alice' greet_patched.assert_called_with('Alice') assert example.greet('Bobby') == 'hello Bobby' greet_patched.assert_called_with('Bobby') assert example.greet('Carl') == 'hello Carl' greet_patched.assert_called_with('Carl') print(greet_patched) print(greet_patched.called) test_greet_function()
I've also written a detailed guide on how to assert that Mock was called with specific arguments.
You can learn more about the related topics by checking out the following tutorials: