Mock 的 autospec 将错误的参数注入到被调用的函数中

2023-12-28

我的理解是autospec此处使用的最简单的形式将检查正在根据所提供的参数进行模拟的函数的签名。其目的是在它们不匹配时引发错误。在下面的代码中,它似乎注入了一个额外的参数——对象本身。为什么使用mock模块的autospec导致此处显示的意外行为? 对于这个问题,我在模块中创建了一个简化版本simplebutton。当它作为主模块运行时,会打印“这不是玩笑”这一行。

#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())

测试模块test_simplebutton包含两个测试都有效。两人都嘲笑callback功能。然而,第二个测试包括autospec=True.

    @unittest.mock.patch('simplebutton._Dialog2.callback',
                         name='callback', autospec=True)

在此测试中,应使用不带参数调用的回调函数必须使用以下参数进行调用dialog否则测试失败。

Edit: 每个人都知道你不会通过以下方式调用方法method(instance) but by instance.method()。那是我的错误。这里需要是instance1.method('instance2') where instance1是模拟和instance2是包含模拟方法的对象。感谢米歇尔·达米科。

        mock_callback.assert_called_once_with(dialog)    

测试套件如下:

#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)

By autospec=True补丁替换对象(在你的情况下method)通过具有相同原始对象签名的模拟。此外,生成的模拟不能是extended:尝试访问原始定义中没有的属性或方法(或者在MagicMock()) 将引发异常。

在第一种情况下(没有autospec=True)您正在用无界方法修补有界方法。当您调用修补方法时,mock_callback被作为函数调用,而不是作为绑定方法dialog object.

当你使用autospec=True in @patch装饰器它用一种新的绑定方法替换了原来的装饰器mock_callback:这就像所有其他绑定方法一样,将由 self 作为第一个参数调用。为了使示例更清晰,我对其进行了更改以更好地解释autospec=True补丁的参数。

import unittest
import unittest.mock

import simplebutton

class Test_Dialog(unittest.TestCase):

    @unittest.mock.patch('simplebutton._Dialog2.callback')
    def test_direct_call_to_callback_by_mocking_1(self, mock_callback):
        dialog = simplebutton._Dialog2()
        dialog.callback()
        mock_callback.assert_called_once_with()
        mock_callback.reset_mock()
        simplebutton._Dialog2.callback()
        mock_callback.assert_called_once_with()

    @unittest.mock.patch('simplebutton._Dialog2.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)
        self.assertRaises(Exception, simplebutton._Dialog2.callback)

        dialog2 = simplebutton._Dialog2()
        dialog.callback()
        dialog2.callback()
        mock_callback.assert_has_calls([unittest.mock.call(dialog), unittest.mock.call(dialog2)])

在第一个测试中,我们显式调用_Dialog2.callback()作为未绑定方法simplebutton._Dialog2.callback()和行为是完全一样的dialog.callback().

在第二个测试中,如果我们尝试像第一个测试一样将其称为未绑定,则会引发异常。此外,如果我们从两个不同的对象调用该方法,我们会发现对同一个模拟的两次不同调用,并且我们可以识别它们。

我希望现在已经清楚会发生什么以及您在使用时应该期待什么autospec=True范围。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mock 的 autospec 将错误的参数注入到被调用的函数中 的相关文章

随机推荐