我们有一个中央模块,模块内部在加载时调用init()函数:
import x
import y
import z
def init():
....
init()
if __name__ == '__main__':
...
这将被引入我们的每个应用程序模块,其语句如下:
if __name__ == '__main__':
import central_module as b
b.do_this()
b.do_that()
init()执行许多不好的事情,特别是建立与数据库的连接。因此,它打破了任何单元测试,我编写的模块期望导入模块并显式调用任何初始化的通常行为。
我通过在顶部添加INITIALIZE变量实现了解决方法:
#INITIALIZE = True
INITIALIZE = False # for DEV/test
if INITIALIZE:
init()
但要求我编辑该文件以运行我的测试或进行开发,然后在我准备提交时恢复更改&推。
出于政治原因,我对修复它没有任何牵引力,例如:
import central_module as b
...
b.init()
b.do_this()
b.do_that()
有什么方法可以在模块加载时更透明地禁用该调用?问题是,在导入模块时,它已经尝试连接到数据库(并且失败了)。
现在我最好的想法是:我可以将INITIALIZE变量移动到先前的导入中,并在我的测试中导入,将initialize设置为FALSE,然后导入central_module。
我将继续致力于政治方面(arg),但是想知道是否有更好的解决方法我可以在不中断所有现有脚本的情况下停止调用init。
答案 0 :(得分:3)
这是我的想法,可能是邪恶的:
ast.parse()
将其解析为AST。imp.new_module()
创建的新模块中,并将其填入sys.modules
。答案 1 :(得分:3)
对INITIALIZE
黑客进行简单更改将是来自环境变量。然后,您永远不必修改代码来运行这些测试,并且在您可以实际修复错误的init之前,不需要更少的hackage。
INITIALIZE = os.environ.get('DO_TERRIBLE_INITIALIZE', False)
if INITIALIZE:
....
值可以是任何东西,只要它的设置。
export DO_TERRIBLE_INITIALIZE=ohgodwhy
答案 2 :(得分:1)
如果您想在测试和生产环境中使用不同的行为,则使用环境变量是标准的:
import os
if os.getenv("MYAPPENV") != "test":
init()
然后你只需要在开发时将MYAPPENV设置为“test”,并且init()不会在加载时运行;如果该变量未在环境中设置,或者具有“test”以外的值,则您将获得默认行为。而且您不必经常重新编辑模块的源文件。
答案 3 :(得分:0)
由于问题是特定于测试的,我看到它的方式,应该调用init,但是在它上面做了坏事(外部程序)被伪代码替换。我认为你不应该避免调用init。