mock.patch 忽略完全导入的函数的原因是什么?
What is the reason that mock.patch ignores a fully imported function?
今天我意识到 unittest.mock.patch
如何导入函数很重要。根据使用的方式,mock.patch
调用有效或被忽略。在 Python 中,我们通常导入一个函数:
- 像
import os
或 这样的导入语句
- 一个
from ... import ...
语句,如from os import system
如果我使用 import os
,mock.patch
就像一个魅力,但它
如果我修补 from os import system
,则会被忽略。
示例 1:使用导入
import os
from unittest import mock
def echo():
os.system('echo "Hello"')
with mock.patch('os.system') as mocked:
print(mocked)
mocked.side_effect = Exception('Patch works!')
echo()
示例 1 的输出
<MagicMock name='system' id='140037358656760'>
Traceback (most recent call last):
File "/.../config/scratches/scratch_7.py", line 12, in <module>
echo()
File "/.../config/scratches/scratch_7.py", line 6, in echo
os.system('echo "Hello"')
File "/.../python3.5/unittest/mock.py", line 917, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "/.../python3.5/unittest/mock.py", line 973, in _mock_call
raise effect
Exception: Patch works!
示例 2:使用全功能导入和自导入
当我完全导入 os.system
时,mock.patch
会忽略 mocked.side_effect
。
from os import system
from unittest import mock
def echo():
system('echo "Hello"')
with mock.patch('os.system') as mocked:
print(mocked)
mocked.side_effect = Exception('Patching does not work!')
echo()
print('Patch was ignored!')
示例 2 的输出
<MagicMock name='system' id='139851175427376'>
Hello
Patch was ignored!
在这两种情况下,我都没有收到错误,并且 mock
可以找到 os.system
作为有效路径。但是,在第二种情况下,该功能未正确修补。
- 为什么
mock.patch
没有给第二个例子中的函数打补丁?
- 是否有任何具体实施原因导致第二个补丁不起作用?
当你执行 from os import system
时,你会得到一个名为 system
的变量指向 os.system
函数。稍后,您通过修补 分配 一个不同的函数给 os.system
,但 system
继续指向旧函数。这与以下工作的原因相同:
tmp = a
a = b
b = tmp
在第一个示例中没有发生,因为您在模拟之前引用了 os.system
。要修复您的第二个示例,我将使用以下内容:
from os import system
from unittest import mock
def echo():
system('echo "Hello"')
with mock.patch('__main__.system') as mocked:
print(mocked)
mocked.side_effect = Exception('Patching does not work!')
echo()
print('Patch was ignored!')
这样您就可以确保修补正确的参考。这是一种相当常见的模式。如果 echo
函数位于名为 echo.py
的文件中,补丁调用将类似于 with mock.patch('echo.system')
.
今天我意识到 unittest.mock.patch
如何导入函数很重要。根据使用的方式,mock.patch
调用有效或被忽略。在 Python 中,我们通常导入一个函数:
- 像
import os
或 这样的导入语句
- 一个
from ... import ...
语句,如from os import system
如果我使用 import os
,mock.patch
就像一个魅力,但它
如果我修补 from os import system
,则会被忽略。
示例 1:使用导入
import os
from unittest import mock
def echo():
os.system('echo "Hello"')
with mock.patch('os.system') as mocked:
print(mocked)
mocked.side_effect = Exception('Patch works!')
echo()
示例 1 的输出
<MagicMock name='system' id='140037358656760'>
Traceback (most recent call last):
File "/.../config/scratches/scratch_7.py", line 12, in <module>
echo()
File "/.../config/scratches/scratch_7.py", line 6, in echo
os.system('echo "Hello"')
File "/.../python3.5/unittest/mock.py", line 917, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "/.../python3.5/unittest/mock.py", line 973, in _mock_call
raise effect
Exception: Patch works!
示例 2:使用全功能导入和自导入
当我完全导入 os.system
时,mock.patch
会忽略 mocked.side_effect
。
from os import system
from unittest import mock
def echo():
system('echo "Hello"')
with mock.patch('os.system') as mocked:
print(mocked)
mocked.side_effect = Exception('Patching does not work!')
echo()
print('Patch was ignored!')
示例 2 的输出
<MagicMock name='system' id='139851175427376'>
Hello
Patch was ignored!
在这两种情况下,我都没有收到错误,并且 mock
可以找到 os.system
作为有效路径。但是,在第二种情况下,该功能未正确修补。
- 为什么
mock.patch
没有给第二个例子中的函数打补丁? - 是否有任何具体实施原因导致第二个补丁不起作用?
当你执行 from os import system
时,你会得到一个名为 system
的变量指向 os.system
函数。稍后,您通过修补 分配 一个不同的函数给 os.system
,但 system
继续指向旧函数。这与以下工作的原因相同:
tmp = a
a = b
b = tmp
在第一个示例中没有发生,因为您在模拟之前引用了 os.system
。要修复您的第二个示例,我将使用以下内容:
from os import system
from unittest import mock
def echo():
system('echo "Hello"')
with mock.patch('__main__.system') as mocked:
print(mocked)
mocked.side_effect = Exception('Patching does not work!')
echo()
print('Patch was ignored!')
这样您就可以确保修补正确的参考。这是一种相当常见的模式。如果 echo
函数位于名为 echo.py
的文件中,补丁调用将类似于 with mock.patch('echo.system')
.