简体   繁体   English

在Python中使用/ import语句进行模拟修补

[英]Mock patching from/import statement in Python

I am trying to get mock.patch to work on the following piece of sample code: 我试图让mock.patch处理以下示例代码:

from mock import patch
from collections import defaultdict

with patch('collections.defaultdict'):
  d = defaultdict()
  print 'd:', d

This outputs the following: 这输出如下:

d: defaultdict(None, {})

Which means that defaultdict was not patched. 这意味着defaultdict没有修补。

If I replace the from/import statement with a straight import statement it works: 如果我用直接导入语句替换from / import语句,它可以工作:

from mock import patch
import collections

with patch('collections.defaultdict'):
 d = collections.defaultdict()
 print 'd:', d

Output is: 输出是:

d: <MagicMock name='defaultdict()' id='139953944084176'>

Is there any way to patch a call using from/import? 有没有办法使用from / import修补呼叫?

Thank you 谢谢

If you're patching something in the same module, you can use __main__ : 如果您在同一模块中修补某些内容,则可以使用__main__

from mock import patch
from collections import defaultdict

with patch('__main__.defaultdict'):
    d = defaultdict()
    print 'd:', d

If you're mocking something for an imported module, however, you'll want to use that module's name so the correct reference (or name) is patched: 但是,如果您要为导入的模块进行模拟,则需要使用该模块的名称,以便修补正确的引用(或名称):

# foo.py

from collections import defaultdict

def bar():
    return defaultdict()


# foo_test.py    

from mock import patch
from foo import bar

with patch('foo.defaultdict'):
    print bar()

The point here is that patch wants the full path to the thing it is patching. 这里的要点是补丁需要完整的路径来修补它。 This just looks a little weird when patching something in the current module, since folks don't often use __main__ (or have to refer to the current module, for that matter). 当在当前模块中修补某些内容时,这看起来有点奇怪,因为人们不经常使用__main__ (或者必须引用当前模块)。

patch works by patching names . patch通过修补名称来工作 You can't achieve anything by patching the name collections.defaultdict if you are using the name defaultdict (in the local namespace) to access the object. 如果使用名称defaultdict (在本地命名空间中)来访问对象,则无法通过修改名称collections.defaultdict来实现任何目的。 See the documentation at http://www.voidspace.org.uk/python/mock/patch.html#id1 . 请参阅http://www.voidspace.org.uk/python/mock/patch.html#id1上的文档。

The names can be very confusing in this case. 在这种情况下,名称可能非常混乱。 We always want to mock a class definition in a namespace. 我们总是希望在命名空间中模拟类定义。 The namespace is the module in which the import takes place. 命名空间是导入发生的模块。 The class definition is the name used in that namespace. 类定义是该命名空间中使用的名称。

Let's take a concrete example: 我们来看一个具体的例子:

  • myproj.utilities module contains Actor class myproj.utilities模块包含Actor类
  • myproj.application imports this as from myproj.utilities import Actor myproj.application from myproj.utilities import Actor
  • my test should execute my.proj.application and mock our Actor 我的测试应该执行my.proj.application并模拟我们的Actor

myproj.utilities.py myproj.utilities.py

class Actor:
    def __init__(name):
        self.name = name

myproj.application.py myproj.application.py

from myproj.utilities import Actor

class App:
    def __init__(name):
        self.actor = Actor(name)

test code 测试代码

from mock import patch
from myproj.application import App

test:
  # format: patch('<namespace>.<Class>')
  # the namespace in which we with to mock
  # the class definition we wish to mock
  with patch('myproj.application.Actor'):
      app = App('Someone')
      print( type(app.actor) ) # expect a MagicMock

I tried several other approaches and this one works well for me. 我尝试了其他几种方法,这个方法对我很有用。 I have not tests the code above but instead generalized it from my own specific case. 我没有测试上面的代码,而是从我自己的特定情况推广它。 So, it might be a little off. 所以,它可能有点偏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM