模拟嘲笑忽略完全导入的功能的原因是什么?

时间:2018-07-31 13:27:17

标签: python python-3.x python-unittest python-mock

今天,我意识到导入函数对于unittest.mock.patch很重要。根据使用的方式,mock.patch调用可以工作或被忽略。在Python中,我们通常使用以下命令导入函数:

  • import os
  • 之类的导入语句
  • 一个from ... import ...之类的from os import system语句

如果我使用mock.patchimport os就像一个超级按钮,但是它 如果我修补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不修补该函数?
  • 第二个补丁不起作用,是否有实现特定的原因?

1 个答案:

答案 0 :(得分:3)

执行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')