如何在Python中将对象注入另一个命名空间?
我正在为办公室里其他人写的代码编写一些单元测试。虽然我对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 个回答
你难道不能用另一个函数来覆盖原来的函数吗?
在Python中没有常量的概念,你可以改变任何东西,甚至可以把 True = False
这样的事情做了。
在Python中,命名空间在同一个范围内并不是很严格。你只需要在同一个范围内用新的变量名覆盖掉原来的变量名(或者直接覆盖掉类本身),这样就可以了。
至于你替换的内容是否表现得一样,那就要看你怎么做了……
如果你的测试代码和 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
中的一个引用,所以你所做的任何更改都是全局可见的。
不过我觉得这样做有点像是小技巧,但这是我能想到的最好方法。