gpt4 book ai didi

python - Mock 的 autospec 将错误的参数注入(inject)到被调用的函数中

转载 作者:太空宇宙 更新时间:2023-11-04 01:10:43 25 4
gpt4 key购买 nike

我的理解是,此处使用的最简单形式的 autospec 将根据提供的参数检查被模拟的函数的签名。其目的是在它们不匹配时引发错误。在下面的代码中,它似乎注入(inject)了一个额外的参数——对象本身。为什么使用 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 参数调用,否则测试将失败。

编辑: 每个人都知道您不是通过method(instance) 调用方法,而是通过instance .方法()。那是我的错误。这里需要是 instance1.method('instance2'),其中 instance1 是模拟,instance2 是包含模拟方法的对象。为此感谢 Michele d'Amico。

        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)

最佳答案

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

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

当你在 @patch 装饰器中使用 autospec=True 时,它会用新的绑定(bind)方法 mock_callback 替换原来的方法:这就像所有其他绑定(bind)方法,并将作为第一个参数由自身调用。为了让示例更清楚,我更改了它以更好地解释 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)])

在第一个测试中,我们通过 simplebutton._Dialog2.callback() 显式调用 _Dialog2.callback() 作为未绑定(bind)的方法,行为正是与 dialog.callback() 相同。

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

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

关于python - Mock 的 autospec 将错误的参数注入(inject)到被调用的函数中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27878750/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com