为什么unittest的`mock.patch.start`会重新运行启动补丁程序的函数?

问题描述 投票:0回答:1

假设我们有两个文件:

to_patch.py

from unittest.mock import patch

def patch_a_function():
    print("Patching!")
    patcher = patch("to_be_patched.function")
    patcher.start()
    print("Done patching!")

to_be_patched.py

from to_patch import patch_a_function

def function():
    pass

patch_a_function()
function()

我们跑步

python -m to_be_patched
。这将输出:

Patching!
Patching!
  1. 为什么没有打印
    Done patching!
  2. 为什么
    Patching!
    打印了两次?

我已经将答案缩小到(2);对

patch.start
的调用似乎再次触发了
patch_a_function
。我怀疑这是因为它是在
to_be_patched.py
中导入的,但我不确定为什么该函数本身会第二次运行。同样,我不确定为什么在对
Done patching!
的两次调用中都没有到达
patch_a_function
线。
patcher.start()
不能阻塞,因为程序可以很好地退出而不是挂在那里......对吗?

python python-unittest patch monkeypatching python-unittest.mock
1个回答
0
投票

此处出现的问题与

patcher.start()
无关,而是由于循环导入并从脚本顶层调用
patch_a_function
造成的。

当您运行

to_be_patched
时,它会调用
patch_a_function

现在在

patch_a_function
patcher = patch("to_be_patched.function")
中需要导入
to_be_patched
,当它被调用时,它会再次调用
patch_a_function

这次调用

patch("to_be_patched.function")
时,它不会重新导入
to_be_patched
,因为它已经导入,因此从此时开始脚本将按预期继续。

您可以将步骤描述为:

 1. CALL patch_a_function
 2. print("Patching!")
 3. CALL `patch("to_be_patched.function")`
 4. `patch` CALLS __import__ of `to_be_patched`
 5. `to_be_patched` is not imported yet so import module
 6. During the import CALL patch_a_function
 7. print("Patching!")
 8. CALL `patch("to_be_patched.function")`
 9. `patch` CALLS __import__ of `to_be_patched`
 10. `to_be_patched` is already imported
 11. Finish the rest of second time called 
 12. CALL patcher.start()
 13. print("Done patching!")
 14. CALL function() (still it is done since we import the module) 
 15. CALL patcher.start()
 16. print("Done patching!")
 17. CALL function()

如果您想解决

to_be_patched
中的问题,请在
if __name__ == '__main__'
语句中调用函数:

from to_patch import patch_a_function

def function():
    pass

if __name__ == '__main__':
    patch_a_function()
    function()

以下是有关顶级代码环境的更多信息:https://docs.python.org/3/library/__main__.html

© www.soinside.com 2019 - 2024. All rights reserved.