首页 > 解决方案 > 通过引用而不是通过名称字符串修补对象?

问题描述

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

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

但是,由于传递给补丁装饰器的值是一个字符串,我并没有从 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()
    # ...

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

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

标签: pythonunit-testingmockingpython-unittest

解决方案


修补工作通过在名称被查找的名称空间中替换

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

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

因此,您从根本上需要修补一个名称,没有直接修补引用。


推荐阅读