Syntax#
Here we look at different syntax options for performing mocking.
import unittest
Mock object#
You can define the behaviour of any object you like. Just pass a Mock()
instance instead.
The following cell defines a class that can perform optional operations on the list using the list_operation
method.
class Example:
def __init__(self, list_operation):
self.list_operation = list_operation
def call_fun(self, lst):
return self.list_operation(lst)
Now suppose you want to write test to this class and check that list_operation
has been called in the correct way.
Just create Mock()
instance and pass it insead of the function that have to be specified for Example
in constructor.
The following cell shows an example that checks the output of Example.call_fun
and that everything passed correctly.
class TestExample(unittest.TestCase):
def test_ok(self):
# Creating mock and difining it's behaviour
mock_list_operation = unittest.mock.Mock()
mock_list_operation.return_value = "mocked result"
example = Example(mock_list_operation)
sample_list = [1, 2, 3]
result = example.call_fun(sample_list)
# Assert that the result is as expected
self.assertEqual(result, "mocked result")
# Assert that the mock was called with the correct arguments
mock_list_operation.assert_called_once_with(sample_list)
def test_fail(self):
'''
And to be sure that evertything
works lets try example that fails
'''
mock_list_operation = unittest.mock.Mock()
mock_list_operation.return_value = "mocked result"
example = Example(mock_list_operation)
example.call_fun([10,20,30])
mock_list_operation.assert_called_with([3,2,1])
ans = unittest.main(argv=[''], verbosity=2, exit=False)
del TestExample
test_fail (__main__.TestExample)
And to be sure that evertything ... FAIL
test_ok (__main__.TestExample) ... ok
======================================================================
FAIL: test_fail (__main__.TestExample)
And to be sure that evertything
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/ipykernel_279798/3126998038.py", line 33, in test_fail
mock_list_operation.assert_called_with([3,2,1])
File "/usr/lib/python3.10/unittest/mock.py", line 929, in assert_called_with
raise AssertionError(_error_message()) from cause
AssertionError: expected call not found.
Expected: mock([3, 2, 1])
Actual: mock([10, 20, 30])
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (failures=1)
As expected, test_ok
ran fine and test_fail
failed.
Patch#
You can change the behavior of an existing function or method by patching it with unittest.mock.patch
. You just need to specify the target
, which refers to an object in Python. Find out more in the specific page.
The following cell defines a function that we’ll patch shortly. It’s just a regular function with an obvious output.
def some_function(a, b):
return a + b
print(some_function(3, 2))
5
The following cell wraps the function with the unittest.mock.patch
context, where the path to that function is specified:
with unittest.mock.patch("__main__.some_function") as patch:
print(type(patch))
patch.return_value = "hello from patch"
print(some_function(3, 2))
<class 'unittest.mock.MagicMock'>
hello from patch
The target variable of the context manager - patch
here - is of type unittest.mock.MagicMock
and actually defines the behavior of the function specified as the target. Thus, calling some_function
returns the value specified in the return_value
attribute.