Python 如何模拟导入
模块Python 如何模拟导入,python,mocking,python-import,Python,Mocking,Python Import,模块A顶部包括import B。但是,在测试条件下,我希望在A(模拟A.B)中B,并完全避免导入B 事实上,B不是故意安装在测试环境中的 A是被测单元。我必须导入A及其所有功能B是我需要模拟的模块。但是,如果A做的第一件事是导入B,我如何在A中模拟B,并阻止A导入真正的B (没有安装B的原因是我使用pypy进行快速测试,不幸的是B还不能与pypy兼容。) 如何做到这一点?您可以在导入A之前分配给sys.modules['B'],以获得所需: 测试.py: import sys sys.modul
A
顶部包括import B
。但是,在测试条件下,我希望在A
(模拟A.B
)中B
,并完全避免导入B
事实上,B
不是故意安装在测试环境中的
A
是被测单元。我必须导入A
及其所有功能<代码>B是我需要模拟的模块。但是,如果A
做的第一件事是导入B
,我如何在A
中模拟B
,并阻止A
导入真正的B
(没有安装B的原因是我使用pypy进行快速测试,不幸的是B还不能与pypy兼容。)
如何做到这一点?您可以在导入
A
之前分配给sys.modules['B']
,以获得所需:
测试.py:
import sys
sys.modules['B'] = __import__('mock_B')
import A
print(A.B.__name__)
import B
import sys
sys.modules['B'] = Mock()
import A
A.py:
import sys
sys.modules['B'] = __import__('mock_B')
import A
print(A.B.__name__)
import B
import sys
sys.modules['B'] = Mock()
import A
注:B.py不存在,但在运行test.py时
不会返回任何错误,并且打印(A.B.\uuuuu name\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您仍然需要在模拟B
的实际函数/变量等的位置创建一个mock_B.py
,或者您可以直接分配一个mock()
:
测试.py:
import sys
sys.modules['B'] = __import__('mock_B')
import A
print(A.B.__name__)
import B
import sys
sys.modules['B'] = Mock()
import A
如果您执行导入模块b
,则实际上是在调用内置方法\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
ModuleB = __import__('ModuleB', globals(), locals(), [], -1)
您可以通过导入\uuuuuuuuuuu内置\uuuuu
模块覆盖此方法,并围绕\uuuuuuuuu内置\uuuuuuu.\uuuuuuuuu导入
方法制作包装。或者您可以从imp
模块中使用NullImporter
钩子。捕获异常并在except
-块中模拟模块/类
指向相关文档的指针:
我希望这有帮助。高度建议您进入python编程更为神秘的领域,并且a)充分理解您真正想要实现的目标,b)彻底理解其含义非常重要。我意识到我来这里有点晚了,但这里有一种有点疯狂的方法,可以通过mock
库来自动执行此操作:
(下面是一个示例用法)
之所以如此复杂,是因为当导入发生时python基本上就是这样做的(例如herp.derp import foo中的)
sys.modules['herp']
是否存在?否则请导入它。如果仍然不importorror
sys.modules['herp.derp']
是否存在?否则请导入它。如果仍然不importorror
获取sys.modules['herp.derp']
的属性foo
。Elseimportorror
foo=sys.modules['herp.derp'].foo
这种拼凑在一起的解决方案有一些缺点:如果其他东西依赖于模块路径中的其他东西,这种方法会把它搞糟。此外,这只适用于正在内联导入的内容,例如
def foo():
import herp.derp
或
内置的\uuuu导入\uuuu
可以使用“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\u mock.func()
b_mock.func.return_value = 'spam'
A.a() # returns 'spam'
Python 3的注意事项:
如中所述,\uuuuuuuuuuuuuuu
现在命名为builtins
:
将模块\uuuuuuuuuuuuuuu
重命名为builtins
(删除下划线,添加“s”)
如果用Python 3的builtins
替换\uuuuuuuuuuuuuuuuuuuu
,则此答案中的代码可以正常工作
如何模拟导入(模拟A.B)?
模块A的顶部包括导入B
简单,只需在sys.modules中模拟库,然后再导入:
if wrong_platform():
sys.modules['B'] = mock.MagicMock()
sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
然后,只要A
不依赖于从B的对象返回的特定类型的数据:
import A
应该就行了
您还可以模拟导入A.B
:
即使您有子模块,也可以这样做,但您需要模拟每个模块。假设你有这个:
from foo import This, That, andTheOtherThing
from foo.bar import Yada, YadaYada
from foo.baz import Blah, getBlah, boink
要模拟,只需在导入包含上述内容的模块之前执行以下操作:
if wrong_platform():
sys.modules['B'] = mock.MagicMock()
sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
(我的经验:我有一个依赖项,它在一个平台Windows上工作,但在Linux上不工作,我们在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)
然后代码需要一些时间来运行,就像实际的方法一样。我找到了用Python模拟导入的好方法。这是我在我的Django应用程序中使用的Eric的Zaadi解决方案
我有一个类SeatInterface
,它是Seat
模型类的接口。
因此,在我的seat\u接口
模块中,我有这样一个导入:
from ..models import Seat
class SeatInterface(object):
(...)
我想用mockedSeat
类作为FakeSeat
为SeatInterface
类创建独立的测试。问题是——当Django应用程序关闭时,tu如何脱机运行测试。我有以下错误:
配置不正确:请求设置BASE\u DIR,但设置不正确
配置。您必须定义环境变量
DJANGO_SETTINGS_模块或调用设置。访问前配置()
设置
在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.002s内运行1次测试
嗯
艾伦·霍尔的回答对我很有用。
我只想提一件重要的事
如果在A.py中
从B.C.D导入E
然后在test.py
中,必须模拟路径上的每个模块,否则会得到ImportError
sys.modules['B'] = mock.MagicMock()
sys.modules['B.C'] = mock.MagicMock()
sys.modules['B.C.D'] = mock.MagicMock()
我