【问题标题】:What is the reason that mock.patch ignores a fully imported function?mock.patch 忽略完全导入函数的原因是什么?
【发布时间】:2018-07-31 13:27:16
【问题描述】:

今天我意识到 unittest.mock.patch 如何导入函数很重要。根据使用的方式,mock.patch 调用工作或被忽略。在 Python 中,我们通常导入一个函数:

  • import os 这样的导入语句或
  • from ... import ... 声明如from os import system

如果我使用import osmock.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没有修补第二个例子中的函数?
  • 是否存在导致第二个补丁不起作用的具体实施原因?

【问题讨论】:

  • 当对象已经被导入当前命名空间时,通常你会使用patch.object。不过,它可能不适用于 system,因为它将是内置/只读的。

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


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2012-10-06
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    • 2017-04-10
    相关资源
    最近更新 更多