其他模块使用的假模块
有没有办法可以伪造一个模块,这个模块是我在测试中使用的其他模块所引用的?
举个例子:这是我的 test.py 文件:
import unittest
import module1
//test code here
module1.some_method()
//test code here
这是 module1.py 文件:
import module_i_want_to_fake
//module code here
根据这个例子,问题是:我该如何在 test.py 中伪造 module_i_want_to_fake
这个模块呢?
2 个回答
0
在Python3中,我这样做:
在一个模块中创建一个简单的假类
# module test.py
thismodule = sys.modules[__name__]
setattr(thismodule, "something", type("something", (), {}))
这很不错,但你可能更想从一个配置数据文件生成它。
从配置文件中在模块中创建假类
# module test.py
import configparser
cfg = configparser.ConfigParser()
cfg.read("/path/to/fname.ini")
for section in cfg.sections():
name = cfg[str(section)]['name']
setattr(thismodule, name, type(name, (), {}))
好的,现在我们在module1中试试
# Import only the main module
import test
# now you can use as you want
test.something
玩得开心!!
3
当你使用 import foo
时,如果 sys.modules['foo']
已经存在,解释器就会直接返回这个已经存在的模块,而不是重新导入一遍。
所以,要想伪装 module1
的 import
语句,只需在加载 module1
之前获取到它的值。这种方法有点小技巧,但非常简单。例如:
mytest.py:
import sys
import unittest
import my_fake_module
sys.modules['module_i_want_to_fake'] = my_fake_module
import module1
//test code here
module1.some_method()
//test code here
module1.py:
import module_i_want_to_fake
print(module_i_want_to_fake)
这样会打印出类似下面的内容:
<module 'my_fake_module' from 'my_fake_module.pyc'>
如果你需要更彻底地伪装 module1
(即使它试图检查模块),你可以创建一个新模块(通过 types.ModuleType
),用 my_fake_module
的代码,但名字改成 'module_i_want_to_fake'
,以及你想要的其他修改。
如果你需要更动态地处理这个问题,而不是提前静态地重命名模块,你可以建立一个导入钩子,具体可以参考 PEP 302。这需要你重新实现一部分导入机制,在 Python 2.x 中这非常麻烦,但在 3.1 及以上版本中,使用 importlib
会简单很多。
幸运的是,通常情况下,你不需要做这两种事情。