为了测试查询环境的内容(例如os.getenv
,sys.version
等),进行查询通常比实际伪造环境更方便。这是一个上下文管理器,它一次为一个os.getenv
调用执行此操作:
from __future__ import with_statement
from contextlib import contextmanager
import os
@contextmanager
def fake_env(**fakes):
'''fakes is a dict mapping variables to their values. In the
fake_env context, os.getenv calls try to return out of the fakes
dict whenever possible before querying the actual environment.
'''
global os
original = os.getenv
def dummy(var):
try: return fakes[var]
except KeyError: return original(var)
os.getenv = dummy
yield
os.getenv = original
if __name__ == '__main__':
print os.getenv('HOME')
with fake_env(HOME='here'):
print os.getenv('HOME')
print os.getenv('HOME')
但这仅适用于os.getenv
,如果我允许具有多个参数的函数,语法会变得有点笨拙。我想在ast
和code
/ exec
/ eval
之间我可以扩展它以使函数覆盖作为参数,但不是干净利落。此外,我将前往Greenspun的第十名。还有更好的方法吗?
答案 0 :(得分:4)
您可以轻松地将os.getenv
本身作为第一个参数传递,然后在上下文管理器中多分析它比ast
,code
等更简单等:
>>> os.getenv.__name__
'getenv'
>>> os.getenv.__module__
'os'
之后,为了合理的通用目的,您可以返回结果对象,或者从参数(可能是其元组)到结果的映射。 faker
上下文管理器也可以选择接受用于伪造的callable。
例如,最简单:
import sys
def faker(original, fakefun):
original = os.getenv
themod = sys.modules[original.__module__]
thename = original.__name__
def dummy(*a, **k):
try: return fakefun(*a, **k)
except BaseException: return original(*a, **k)
setattr(themod, thename, dummy)
yield
setattr(themod, thename, original)
您的具体示例可能会变为:
with faker(os.getenv, dict(HOME='here').__getitem__):
...
当然,如果需要更多复杂性,则可能需要更加复杂。你想传播某些异常,而不是向原始函数进行扩展,或者提供一些常见的情况,其中提供一个假冒的可调用程序是笨重的,等等。但是,没有理由这样一般的骗子需要比你的特定的更复杂 。
答案 1 :(得分:1)
为什么不编写自己的(假)sys
,os
和& c。模块?
import fakeSys as sys