我正在尝试让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修补电话?
谢谢
答案 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)
在这种情况下,名称可能会非常混乱。我们一直想在名称空间中模拟类定义。命名空间是在其中进行导入的模块。类定义是该命名空间中使用的名称。
让我们举一个具体的例子:
from myproj.utilities import Actor
class Actor:
def __init__(name):
self.name = name
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
我尝试了其他几种方法,这种方法对我来说效果很好。我没有测试上面的代码,而是根据自己的具体情况对其进行了概括。因此,可能会有些偏离。