Mock patching from/import statement in Python

余生颓废 提交于 2019-12-03 08:26:24

问题


I am trying to get mock.patch to work on the following piece of sample code:

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.

If I replace the from/import statement with a straight import statement it works:

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?

Thank you


回答1:


If you're patching something in the same module, you can use __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).




回答2:


patch works by patching names. 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. See the documentation at http://www.voidspace.org.uk/python/mock/patch.html#id1 .




回答3:


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.application imports this as from myproj.utilities import Actor
  • my test should execute my.proj.application and mock our 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)

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.



来源:https://stackoverflow.com/questions/11351382/mock-patching-from-import-statement-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!