'How to get the arguments passed to various calls from call_args_list?

I'm trying to use call_args_list to get the arguments passed to a certain function when it is called multiple times. I'm using this:

call_args_list = mock.add_row.call_args_list

Then I get a list that looks like this: [call('A', []), call('B', []), call('C', ['err'])].

If I only want to check that the second call doesn't have an error in the second argument and the third does, I need to somehow access the items within the call. Does anyone know how can I peel these call objects to get the items inside?



Solution 1:[1]

import unittest

import mock


class TestCase(unittest.TestCase):
    def test_my_func(self):
        m = mock.MagicMock()
        m.add_row('A', [])
        m.add_row('B', [])
        m.add_row('C', ['err'])

        calls = m.add_row.call_args_list

        _first_arg, second_arg = calls[1][0]
        self.assertNotEqual(second_arg, ['err'])

        _first_arg, second_arg = calls[2][0]
        self.assertEqual(second_arg, ['err'])


if __name__ == '__main__':
    unittest.main()

Solution 2:[2]

def test_call_args(self):
    m = mock.Mock()
    m.add_row('A', ['a', 'aa'])
    m.add_row('B', ['b', 'bb', 'bbb'])
    m.add_row('C', ['c', 'cc', 'ccc', 'err'])

    # args is a tuple, the second call
    args, kwargs = m.add_row.call_args_list[1]
    # the second arg is a list
    self.assertTrue('err' not in args[1])

    # third call
    args, kwargs = m.add_row.call_args_list[2]
    self.assertTrue('err' in args[1])

Solution 3:[3]

It doesn't appear to be (well) documented, but mock defines a subclass of tuple named _Call, instances of which are what you see in call_args_list. The first element is the name of the function, the second is a tuple of positional arguments, and the third a dict of keyword arguments.

Solution 4:[4]

There are ways of digging into these _Call objects, but only to some extent. What if, for example, a parameter in a called mocked method is itself a Mock?

Consider this:

def test_create_and_show_main_window_should_make_main_window_vis(qtbot):
    with mock.patch('PyQt5.QtWidgets.QApplication'):
        with mock.patch.object(MainWindow.the(), 'show') as mock_show:
            with mock.patch('sys.exit') as mock_exit:
                
                main_window_class.create_and_show_main_window()
        
    mock_show.assert_called_once()
    mock_exit.assert_called_once()
    call = mock_exit.call_args_list[0]
    call_arg = call.args[0]
    assert call_arg._extract_mock_name() == 'QApplication().exec()'

In the above I want to test the following lines in my app code:

app_instance = QtWidgets.QApplication(sys.argv)
MainWindow.the().show()
sys.exit(app_instance.exec())

... it turns out that, in the above, call_arg is of type unittest.mock.MagicMock and that repr(call_arg) is "<MagicMock name='QApplication().exec()' id='139817836711216'>".

A MagicMock has a name attribute, but if you try to use it directly it will create a new MagicMock automatically rather than returning it: MagicMocks are slippery, powerful objects. Fortunately, as illustrated above, the method _extract_mock_name has been provided to obtain it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Gang
Solution 3 chepner
Solution 4