My understanding is that autospec
in its simplest form as used here will check the signature of the function which is being mocked against the presented arguments. Its purpose is to raise an error if they do not match. In the code below it seems to inject an additional argument - the object itself. Why does the use of the mock module's autospec
lead to the unexpected behavior shown here?
For this question I've created a simplified version in the module simplebutton
. When it's run as the main module the line, "It's no joke," is printed.
#module simplebutton
import sys
class _Dialog2:
def callback(self):
print("It's no joke")
def main():
dialog = _Dialog2()
dialog.callback()
if __name__ == '__main__':
sys.exit(main())
The test module test_simplebutton
contains two tests both of which work. Both mock the callback
function. The second test, however, includes autospec=True
.
@unittest.mock.patch('simplebutton._Dialog2.callback',
name='callback', autospec=True)
In this test the callback function which should be called with no arguments has to be called with an argument of dialog
otherwise the test fails.
Edit: Everyone knows that you don't call a method by method(instance)
but by instance.method()
. That was my mistake. Here it needs to be instance1.method('instance2')
where instance1
is the mock and instance2
is the object containing the mocked method. Thanks to Michele d'Amico for this.
mock_callback.assert_called_once_with(dialog)
The test suite follows:
#module test_simplebutton
import unittest
import unittest.mock
import simplebutton
class Test_Dialog(unittest.TestCase):
@unittest.mock.patch('simplebutton._Dialog2.callback',
name='callback')
def test_direct_call_to_callback_by_mocking_1(self, mock_callback):
dialog = simplebutton._Dialog2()
dialog.callback()
mock_callback.assert_called_once_with()
@unittest.mock.patch('simplebutton._Dialog2.callback',
name='callback', autospec=True)
def test_direct_call_to_callback_by_mocking_2(self, mock_callback):
dialog = simplebutton._Dialog2()
dialog.callback()
mock_callback.assert_called_once_with(dialog)