不从文件加载python模块

不从文件加载python模块,python,unit-testing,module,import,Python,Unit Testing,Module,Import,我在一个库中有一些python代码,它试图从一个模块中加载一个简单的值,该模块将为使用该库的应用程序提供 from somemodule import simplevalue 通常,使用库的应用程序将具有模块文件,并且一切正常。但是,在此库的单元测试中,该模块不存在。我知道我可以创建一个临时文件,并在运行时将该文件添加到我的路径中,但我很好奇python中是否有一种方法可以将某些内容加载到内存中,从而允许上述导入工作 这更像是好奇,说“将模块添加到您的测试路径”没有帮助:p是的。使用types

我在一个库中有一些python代码,它试图从一个模块中加载一个简单的值,该模块将为使用该库的应用程序提供

from somemodule import simplevalue
通常,使用库的应用程序将具有模块文件,并且一切正常。但是,在此库的单元测试中,该模块不存在。我知道我可以创建一个临时文件,并在运行时将该文件添加到我的路径中,但我很好奇python中是否有一种方法可以将某些内容加载到内存中,从而允许上述导入工作


这更像是好奇,说“将模块添加到您的测试路径”没有帮助:p

是的。使用
types.ModuleType
创建新的模块对象,然后将其添加到
sys.modules

sys.modules["somename"] = types.ModuleType("somename")
然后,您可以执行
导入somename
。如果需要向其中添加类或函数,请在调用测试脚本之前导入它,然后只向其中添加函数:

def myfunc(x, y, z):
    ...

somename.myfunc = myfunc
这应该不言而喻,但以防万一:这在很大程度上是一种学术好奇心。它对测试有一些用途,但除此之外,请坚持以通常的方式导入内容

顺便说一句,我是如何知道这一点的:我遇到了测试中使用的技术,在非Windows系统上为
\u winreg
模块创建一个“存根”。正在使用。

您的被测系统(
sut
,在我的示例中)需要能够处理
somemodule
可能不存在的事实,因此您可以捕获
ImportError

#!/usr/bin/env python

try:
    from somemodule import simplevalue
except ImportError, e:
    if 'somemodule' in e:
        '''We expect that to happen in the unittest but you should log something for when
         this happens in production'''

def fn():
    return simplevalue
然后您可以在unittest中注入一个值:

#!/usr/bin/env python

import unittest
import sut

class T(unittest.TestCase):

    def test_fn(self):
        sut.simplevalue = 42
        self.assertEquals(42, sut.fn())


if __name__ == '__main__':
    unittest.main()

不需要创建模块。没有Python代码关心
somemodule.simplevalue
是否实际上是对模块属性的引用。为此,程序需要检查
somemodule
的类型。为什么要麻烦

由于您只需要模块中的单个值并将其导入到您自己的命名空间中,因此只需定义它:

simplevalue = 42
如果愿意,请先使用
try/except
尝试导入实际模块

try:
    from somemodule import simplevalue
except ImportError:
    simplevalue = 42
如果要导入整个模块,但仅使用一个值,则可以使用类定义命名空间

try:
    import somemodule
except ImportError:
    class somemodule(object):
        simplevalue = 42
现在
somemodule.simplevalue
引用该值,而不管模块是否可用

如果您希望其他也导入
somemodule
的模块将伪造的类视为模块,就像您在单元测试中所做的那样,只需在之后执行以下操作:

import sys
sys.modules["somemodule"] = somemodule

我很高兴我们都选择了42作为
simplevalue
:-)的值,谢谢托马斯,工作得很好。是的,我同意,这不是我想写的代码模式。但是对于这个测试场景,它是正确的。@smullins:不客气。这个警告更多是针对未来的匿名读者,而不是你,因为你听起来好像知道自己在做什么。