其他模块使用的假模块

1 投票
2 回答
1542 浏览
提问于 2025-04-17 18:59

有没有办法可以伪造一个模块,这个模块是我在测试中使用的其他模块所引用的?

举个例子:这是我的 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'] 已经存在,解释器就会直接返回这个已经存在的模块,而不是重新导入一遍。

所以,要想伪装 module1import 语句,只需在加载 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 会简单很多。

幸运的是,通常情况下,你不需要做这两种事情。

撰写回答