Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何模拟导入_Python_Mocking_Python Import - Fatal编程技术网

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
    。Else
    importorror
  • 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):
        (...)
    
    我想用mocked
    Seat
    类作为
    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()