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

时间:2012-07-05 19:38:43

标签: python python-mock

我正在尝试让mock.patch处理以下示例代码:

from mock import patch
from collections import defaultdict

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

这输出以下内容:

d: defaultdict(None, {})

这意味着defaultdict没有打补丁。

如果我用直接导入语句替换from / import语句,它可以工作:

from mock import patch
import collections

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

输出是:

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

有没有办法使用from / import修补电话?

谢谢

3 个答案:

答案 0 :(得分:34)

如果您在同一模块中修补某些内容,则可以使用__main__

from mock import patch
from collections import defaultdict

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

但是,如果您要为导入的模块进行模拟,则需要使用该模块的名称,以便修补正确的引用(或名称):

# 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()

这里的要点是补丁想要修补它的东西的完整路径。在当前模块中修补某些东西时,这看起来有点奇怪,因为人们不经常使用__main__(或者必须参考当前模块)。

答案 1 :(得分:10)

patch通过修补名称来工作。如果使用名称collections.defaultdict(在本地命名空间中)来访问对象,则无法通过修改名称defaultdict来实现任何目的。请参阅http://www.voidspace.org.uk/python/mock/patch.html#id1上的文档。

答案 2 :(得分:1)

在这种情况下,名称可能会非常混乱。我们一直想在名称空间中模拟类定义。命名空间是在其中进行导入的模块。类定义是该命名空间中使用的名称。

让我们举一个具体的例子:

  • myproj.utilities模块包含Actor类
  • myproj.application将其导入为from myproj.utilities import Actor
  • 我的测试应执行my.proj.application并模拟我们的Actor

myproj.utilities.py

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

myproj.application.py

from myproj.utilities import Actor

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

测试代码

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

我尝试了其他几种方法,这种方法对我来说效果很好。我没有测试上面的代码,而是根据自己的具体情况对其进行了概括。因此,可能会有些偏离。