Answers:
您可以sys.modules['B']
在导入之前分配给以A
获得所需的内容:
test.py:
import sys
sys.modules['B'] = __import__('mock_B')
import A
print(A.B.__name__)
A.py:
import B
注意B.py不存在,但是运行时test.py
不会返回错误并显示print(A.B.__name__)
print mock_B
。您仍然必须mock_B.py
在模拟B
实际功能/变量/等的地方创建一个。或者,您可以直接分配一个Mock()
:
test.py:
import sys
sys.modules['B'] = Mock()
import A
sys.modules['B'] = None
但似乎没有用。
mock
,然后致电mock.Mock()
__import__
可以使用'mock'库来模拟内置函数,以实现更多控制:
# Store original __import__
orig_import = __import__
# This will be the B module
b_mock = mock.Mock()
def import_mock(name, *args):
if name == 'B':
return b_mock
return orig_import(name, *args)
with mock.patch('__builtin__.__import__', side_effect=import_mock):
import A
说A
看起来像:
import B
def a():
return B.func()
A.a()
返回b_mock.func()
也可以被嘲笑。
b_mock.func.return_value = 'spam'
A.a() # returns 'spam'
Python 3的注意事项:
如3.0的变更日志所述,__builtin__
现名为builtins
:
将模块重命名
__builtin__
为builtins
(删除下划线,添加“ s”)。
如果更换这个答案的代码工作正常__builtin__
通过builtins
为Python 3。
import_mock
调用get import A
,但没有为其导入的任何东西打电话。
ImportError: No module named '__builtin__'
__builtin__
__builtin__
由builtins
用于python3(docs.python.org/3/whatsnew/3.0.html?highlight=__builtin__)
如何模拟导入(模拟AB)?
模块A在其顶部包括导入B。
容易,只需在导入它之前在sys.modules中模拟该库:
if wrong_platform():
sys.modules['B'] = mock.MagicMock()
然后,只要A
不依赖于从B对象返回的特定类型的数据:
import A
应该工作。
import A.B
:即使您有子模块,此方法也有效,但是您将需要模拟每个模块。说你有这个:
from foo import This, That, andTheOtherThing
from foo.bar import Yada, YadaYada
from foo.baz import Blah, getBlah, boink
要进行模拟,只需在导入包含以上内容的模块之前执行以下操作:
sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
(我的经验:我有一个可以在一个平台Windows上运行的依赖项,但是在运行日常测试的Linux上却不起作用。所以我需要为我们的测试模拟该依赖项。幸运的是,这是一个黑盒子,所以我不需要进行很多互动。)
附录:实际上,我需要模拟花费一些时间的副作用。所以我需要一个对象的方法来睡一秒钟。那会像这样工作:
sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
# setup the side-effect:
from time import sleep
def sleep_one(*args):
sleep(1)
# this gives us the mock objects that will be used
from foo.bar import MyObject
my_instance = MyObject()
# mock the method!
my_instance.method_that_takes_time = mock.MagicMock(side_effect=sleep_one)
然后,就像真实方法一样,代码需要一些时间才能运行。
我意识到我在这里参加聚会有点晚了,但这是一种通过mock
库自动执行此操作的疯狂方法:
(这是一个示例用法)
import contextlib
import collections
import mock
import sys
def fake_module(**args):
return (collections.namedtuple('module', args.keys())(**args))
def get_patch_dict(dotted_module_path, module):
patch_dict = {}
module_splits = dotted_module_path.split('.')
# Add our module to the patch dict
patch_dict[dotted_module_path] = module
# We add the rest of the fake modules in backwards
while module_splits:
# This adds the next level up into the patch dict which is a fake
# module that points at the next level down
patch_dict['.'.join(module_splits[:-1])] = fake_module(
**{module_splits[-1]: patch_dict['.'.join(module_splits)]}
)
module_splits = module_splits[:-1]
return patch_dict
with mock.patch.dict(
sys.modules,
get_patch_dict('herp.derp', fake_module(foo='bar'))
):
import herp.derp
# prints bar
print herp.derp.foo
这是如此荒谬的原因是,当发生导入时,python基本上会这样做(例如from herp.derp import foo
)
sys.modules['herp']
存在?否则导入。如果还没有ImportError
sys.modules['herp.derp']
存在?否则导入。如果还没有ImportError
foo
的sys.modules['herp.derp']
。其他ImportError
foo = sys.modules['herp.derp'].foo
这种被黑客入侵的解决方案有一些缺点:如果模块路径中的其他内容依赖于其他内容,则将其拧紧。而且,这仅适用于内联导入的内容,例如
def foo():
import herp.derp
要么
def foo():
__import__('herp.derp')
我找到了在Python中模拟导入的好方法。这是Eric的Zaadi解决方案,我在Django应用程序中使用了该解决方案。
我有一个类SeatInterface
,它是Seat
模型类的接口。所以在我的seat_interface
模块中,我有这样一个导入:
from ..models import Seat
class SeatInterface(object):
(...)
我想为SeatInterface
模拟Seat
类创建隔离测试FakeSeat
。问题是-在Django应用程序关闭的情况下,tu运行离线测试的方式。我有以下错误:
配置不正确:请求的设置为BASE_DIR,但未配置设置。您必须先定义环境变量DJANGO_SETTINGS_MODULE或调用settings.configure()才能访问设置。
在0.078秒内进行了1次测试
失败(错误= 1)
解决方案是:
import unittest
from mock import MagicMock, patch
class FakeSeat(object):
pass
class TestSeatInterface(unittest.TestCase):
def setUp(self):
models_mock = MagicMock()
models_mock.Seat.return_value = FakeSeat
modules = {'app.app.models': models_mock}
patch.dict('sys.modules', modules).start()
def test1(self):
from app.app.models_interface.seat_interface import SeatInterface
然后测试神奇地运行OK :)
。
在0.002秒内进行1次测试好
如果这样做,import ModuleB
您实际上是在__import__
按以下方式调用内置方法:
ModuleB = __import__('ModuleB', globals(), locals(), [], -1)
您可以通过导入__builtin__
模块并对该方法进行包装来覆盖此__builtin__.__import__
方法。或者,您可以使用模块中的NullImporter
挂钩imp
。捕获异常并在except
-block中模拟您的模块/类。
指向相关文档的指针:
我希望这有帮助。是HIGHLY劝你踏进Python编程的更神秘的周边和一)扎实的了解,你真正要实现和B)的影响的深入理解什么是重要的。
Mock
不会修补某些魔术属性(__%s__
)__name__
。