Python:拦截类加载动作

Ant*_*ong 6 python unit-testing

简介:当导入某个python模块时,我希望能够拦截这个动作,而不是加载所需的类,我想加载我选择的另一个类.

原因:我正在研究一些遗留代码.在开始一些增强/重构之前,我需要编写一些单元测试代码.但是,代码会导入某个模块,该模块在单元测试设置中会失败.(由于数据库服务器依赖性)

Pseduo代码:

from LegacyDataLoader import load_me_data
...
def do_something():
   data = load_me_data()
Run Code Online (Sandbox Code Playgroud)

因此,理想情况下,当python在单元测试中使用上面的导入行时,会加载替代类MockDataLoader.

我还在使用2.4.3.我想有一个我可以操纵的导入钩子

编辑

非常感谢到目前为止的答案.他们都非常有帮助.

一种特殊类型的建议是关于操纵PYTHONPATH.它在我的情况下不起作用.所以我将在这里阐述我的具体情况.

原始代码库以这种方式组织

./dir1/myapp/database/LegacyDataLoader.py
./dir1/myapp/database/Other.py
./dir1/myapp/database/__init__.py
./dir1/myapp/__init__.py
Run Code Online (Sandbox Code Playgroud)

我的目标是在Other模块中增强Other类.但是因为它是遗留代码,所以如果不首先将测试套件捆绑在一起,我会感到很自在.

现在我介绍一下这个单元测试代码

./unit_test/test.py
Run Code Online (Sandbox Code Playgroud)

内容很简单:

from myapp.database.Other import Other

def test1():
            o = Other()
            o.do_something()

if __name__ == "__main__":
            test1()
Run Code Online (Sandbox Code Playgroud)

当CI服务器运行上述测试时,测试失败.这是因为类Other使用LegacyDataLoader,而LegacydataLoader无法从CI框建立与数据库服务器的数据库连接.

现在让我们按照建议添加一个假类:

./unit_test_fake/myapp/database/LegacyDataLoader.py
./unit_test_fake/myapp/database/__init__.py
./unit_test_fake/myapp/__init__.py
Run Code Online (Sandbox Code Playgroud)

将PYTHONPATH修改为

export PYTHONPATH=unit_test_fake:dir1:unit_test
Run Code Online (Sandbox Code Playgroud)

现在测试失败了另一个原因

  File "unit_test/test.py", line 1, in <module>
    from myapp.database.Other import Other
ImportError: No module named Other
Run Code Online (Sandbox Code Playgroud)

它与python解析模块中的类/属性的方式有关

Ale*_*lli 5

您可以通过定义自己的函数并将其分配给来拦截importfrom ... import声明(确保保存先前的值,因为您的覆盖无疑将要委派给它;并且您将需要获取内置对象模块)。__import____builtin__.__import__import __builtin__

例如(特定于Py2.4,因为您要问的是),将以下内容保存在aim.py中:

import __builtin__
realimp = __builtin__.__import__
def my_import(name, globals={}, locals={}, fromlist=[]):
  print 'importing', name, fromlist
  return realimp(name, globals, locals, fromlist)
__builtin__.__import__ = my_import

from os import path
Run Code Online (Sandbox Code Playgroud)

现在:

$ python2.4 aim.py
importing os ('path',)
Run Code Online (Sandbox Code Playgroud)

因此,这使您可以截获所需的任何特定导入请求,并在返回它们之前根据需要更改导入的模块-请参阅此处的规格。这就是您要寻找的“挂钩”,对吗?