如何在Python中将对象注入另一个命名空间?

5 投票
5 回答
2168 浏览
提问于 2025-04-16 03:05

我正在为办公室里其他人写的代码编写一些单元测试。虽然我对Python不是很熟悉,但在基本的单元测试方面我还算顺利。不过,Python中的模拟(mocking)让我有点困惑。

我需要做的是覆盖对ConfigObj的调用,并在任何ConfigObj的调用中注入我自己的模拟配置或测试数据。

settings.py

from configobj import ConfigObj
config = ConfigObj('/etc/myapp/config')

utils.py

from settings import config
"""lots of stuff methods using various config values."""

我想在对utils.py的单元测试中,能够在任何对ConfigObj的调用或者settings.py本身中注入我的内容。

很多模拟库都希望我模拟自己的类,但在这个应用程序中,并没有明确的类。

这样做可以实现吗?还是说Python的命名空间限制太严格,以至于我无法干预我导入的模块所导入的内容?

顺便提一下,我使用的是2.7版本,所以我不能使用我在2.5版本中看到的那些技巧。

5 个回答

0

你难道不能用另一个函数来覆盖原来的函数吗?

在Python中没有常量的概念,你可以改变任何东西,甚至可以把 True = False 这样的事情做了。

1

在Python中,命名空间在同一个范围内并不是很严格。你只需要在同一个范围内用新的变量名覆盖掉原来的变量名(或者直接覆盖掉类本身),这样就可以了。

至于你替换的内容是否表现得一样,那就要看你怎么做了……

3

如果你的测试代码和 settings.py 以及 utils.py 在不同的文件里,你可以创建一个叫 mock.py 的文件。

import configobj

class MockConfigObj(object):
     #mock whatever you wan

configobj.ConfigObj = MockConfigObj

然后在导入任何会用到 settings 的模块之前,先 import mock。这样可以确保 settings.config 是用 MockConfigObj 创建的。如果你想要全局统一的模拟效果,记得在任何导入 configobj 的文件之前先导入它。

这样做的原因是,Python 会把 configobj 存储在 sys.modules 中,并在后续的导入时检查这个模块,而不是直接去读取文件。在 mock.py 中,ConfigObj 只是指向 sys.modules 中的一个引用,所以你所做的任何更改都是全局可见的。

不过我觉得这样做有点像是小技巧,但这是我能想到的最好方法。

撰写回答