假设我有两个文件:
some_module.py
def get_value_1():
return 1
def print_value_1():
print(get_value_1())和主文件main.py
from unittest.mock import patch
import some_module
from some_module import print_value_1, get_value_1
def mocked_value():
return 2
if __name__ == '__main__':
print_value_1() # prints 1
with patch.object(some_module, 'get_value_1', mocked_value):
print_value_1() # prints 2
print(some_module.get_value_1()) # prints 2
print(get_value_1()) # prints 1 - DESIRABLE RESULT IS TO PRINT ALSO 2正如您所看到的,因为我显式地导入了get_value_1函数,所以补丁不能对它起作用。我基本上理解为什么,那是因为它使用了一个引用,并且引用是在主ran之前导入的(通过在每个调用的函数上调用id()来检查它,并查看地址)。我能以某种方式也劫持导入的引用吗?
(只在main.py中打补丁是不够的,我希望在整个项目中都打上补丁,例如在其他一些some_other_module.py中会有:from some_module import get_value_1,当我调用get_value_1()时,它会调用打过补丁的函数并返回值2)
发布于 2020-07-27 23:10:28
如果使用patch或patch.object,则无法修补模块的每个引用。在您的情况下,这将是例如:
if __name__ == '__main__':
print_value_1()
with patch.object(some_module, 'get_value_1', mocked_value):
with patch.object(sys.modules[__name__], 'get_value_1', mocked_value):
print_value_1()
print(some_module.get_value_1())
print(get_value_1())根据应用程序结构的不同,您可以遍历引用要打补丁的函数的所有模块,例如:
def get_modules():
return (sys.modules[__name__], some_module, some_other_module)
if __name__ == '__main__':
patches = []
for module in get_modules():
p = patch.object(module, 'get_value_1', mocked_value)
p.start()
patches.append(p)
print(some_module.get_value_1())
print(some_other_module.get_value_1())
print(get_value_1())
[p.stop() for p in patches]如果事先没有要修补的所有模块,则必须收集需要在运行时修补的所有模块(例如,get_modules变得更加复杂),例如,通过迭代所有加载的模块,找到要按名称修补的函数,并模拟该函数(假设此时所有模块都已加载)。
https://stackoverflow.com/questions/63116720
复制相似问题