通过引用而不是通过名称字符串修补对象?

gol*_*enk 7 python unit-testing mocking python-unittest

修补模块中某些内容的最常见方法似乎是使用类似

from unittest.mock import patch

from mypackage.my_module.my_submodule import function_to_test

@patch('mypackage.my_module.my_submodule.fits.open')
def test_something(self, mock_fits_open)
    # ...
    mock_fits_open.return_value = some_return_value
    function_to_test()
    # ...
Run Code Online (Sandbox Code Playgroud)

然而,由于传递给补丁装饰器的值是一个字符串,我没有从 IDE 中获得很多好处。我无法使用字符串的一部分跳转到定义。我没有得到自动完成(和隐式拼写检查)。也没有完整的重构能力。等等。

使用patch.object我可以更接近我正在寻找的东西。

from unittest.mock import patch

import mypackage.my_module.my_submodule
from mypackage.my_module.my_submodule import function_to_test

@patch.object(mypackage.my_module.my_submodule.fits, 'open')
def test_something(self, mock_fits_open)
    # ...
    mock_fits_open.return_value = some_return_value
    function_to_test()
    # ...
Run Code Online (Sandbox Code Playgroud)

然而,这仍然要求引用对象的名称的最后部分只是一个字符串。有没有一种(好的)方法可以纯粹根据对该对象的引用来修补该对象?也就是说,我希望能够做类似的事情

from unittest.mock import patch

import mypackage.my_module.my_submodule
from mypackage.my_module.my_submodule import function_to_test

@patch.reference(mypackage.my_module.my_submodule.fits.open)
def test_something(self, mock_fits_open)
    # ...
    mock_fits_open.return_value = some_return_value
    function_to_test()
    # ...
Run Code Online (Sandbox Code Playgroud)

wim*_*wim 3

修补的工作原理是在查找名称的命名空间中进行替换

的底层逻辑mock.patch本质上是使用上下文管理的名称隐藏。您可以手动执行相同的操作:

  • 保存与名称关联的原始值(如果有)
  • try覆盖名称
  • 执行被测试的代码
  • finally将名称重置回原始值

因此,您从根本上需要修补名称,而不是直接修补引用。