Syntax

Contents

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.