Rob*_*ers 119
您可以sys.modules['B']在导入之前分配到A以获得所需内容:
test.py:
import sys
sys.modules['B'] = __import__('mock_B')
import A
print(A.B.__name__)
Run Code Online (Sandbox Code Playgroud)
A.py:
import B
Run Code Online (Sandbox Code Playgroud)
注意B.py不存在,但在运行时test.py没有返回错误并print(A.B.__name__)打印mock_B.您仍然需要创建一个mock_B.py模拟B的实际函数/变量/等的位置.或者您可以直接指定Mock():
test.py:
import sys
sys.modules['B'] = Mock()
import A
Run Code Online (Sandbox Code Playgroud)
sie*_*z0r 23
内置__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
Run Code Online (Sandbox Code Playgroud)
说A看起来像:
import B
def a():
return B.func()
Run Code Online (Sandbox Code Playgroud)
A.a()b_mock.func()也可以嘲笑的回报.
b_mock.func.return_value = 'spam'
A.a() # returns 'spam'
Run Code Online (Sandbox Code Playgroud)
Aar*_*all 14
如何模拟导入,(模拟AB)?
模块A在其顶部包括导入B.
很简单,只需在导入之前模拟sys.modules中的库:
if wrong_platform():
sys.modules['B'] = mock.MagicMock()
Run Code Online (Sandbox Code Playgroud)
然后,只要A不依赖于从B对象返回的特定类型的数据:
import A
Run Code Online (Sandbox Code Playgroud)
应该工作.
import A.B:即使您有子模块,这也有效,但您需要模拟每个模块.说你有这个:
from foo import This, That, andTheOtherThing
from foo.bar import Yada, YadaYada
from foo.baz import Blah, getBlah, boink
Run Code Online (Sandbox Code Playgroud)
要进行模拟,只需在导入包含上述模块的模块之前执行以下操作:
sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
Run Code Online (Sandbox Code Playgroud)
(我的经验:我有一个依赖,可以在一个平台上工作,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)
Run Code Online (Sandbox Code Playgroud)
然后代码需要一些时间来运行,就像真正的方法一样.
小智 10
亚伦霍尔的回答对我有用。只想提一件重要的事,
如果A.py你这样做
from B.C.D import E
然后test.py你必须模拟路径上的每个模块,否则你会得到ImportError
sys.modules['B'] = mock.MagicMock()
sys.modules['B.C'] = mock.MagicMock()
sys.modules['B.C.D'] = mock.MagicMock()
Run Code Online (Sandbox Code Playgroud)
我意识到我在这里参加派对有点晚了,但这里有一种疯狂的方式来自动化这个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
Run Code Online (Sandbox Code Playgroud)
这是如此荒谬复杂的原因是当导入发生时python基本上这样做(例如from herp.derp import foo)
sys.modules['herp']存在?否则导入它.如果还没有ImportErrorsys.modules['herp.derp']存在?否则导入它.如果还没有ImportErrorfoo的sys.modules['herp.derp'].其他ImportErrorfoo = sys.modules['herp.derp'].foo这个被黑客攻击的解决方案有一些缺点:如果其他东西依赖于模块路径中的其他东西,这种方法就会将其拧紧.此外,这仅适用于内联导入的内容,例如
def foo():
import herp.derp
Run Code Online (Sandbox Code Playgroud)
要么
def foo():
__import__('herp.derp')
Run Code Online (Sandbox Code Playgroud)
我找到了在 Python 中模拟导入的好方法。这是Eric 的 Zaadi解决方案在这里找到,我只是在我的Django应用程序中使用它。
我有一个类SeatInterface,它是Seat模型类的接口。所以在我的seat_interface模块中,我有这样一个导入:
from ..models import Seat
class SeatInterface(object):
(...)
Run Code Online (Sandbox Code Playgroud)
我想SeatInterface用模拟Seat类为类创建隔离测试FakeSeat。问题是 - 如何离线运行测试,其中 Django 应用程序已关闭。我有以下错误:
ImproperlyConfigured:请求设置 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
Run Code Online (Sandbox Code Playgroud)
然后 test 神奇地运行 OK :)
.
在 0.002 秒内运行 1 次测试好的
| 归档时间: |
|
| 查看次数: |
44077 次 |
| 最近记录: |