我想对在其os.environ
函数中调用__init__()
的类上编写一些测试,并希望使用mock.patch.dict()
来调用os.environ
。我很确定自己过去已经成功完成了此操作,但是在这种情况下我无法使其正常工作。
我整理了这个问题的一个副本。这是要测试的课程:
import os
class Widget():
def __init__(
self,
foo: str = os.environ['SOME_VAR']
):
self.bar = foo
def func1(self):
return self.bar
和我的测试类(在目录tests
中):
import unittest
import mock
from widget import Widget
@mock.patch.dict(
"widget.os.environ",
{"SOME_VAR": "qwerty"}
)
class TestWidget(unittest.TestCase):
def test1(self):
widget1 = Widget()
assert widget1.func1() == "qwerty"
我使用pytest
作为测试运行程序。运行测试时出现错误:
tests / test_widget.py:3:在
中 从窗口小部件导入窗口小部件
widget.py:4:在
中 Widget()类:
widget.py:7:在Widget中
foo:str = os.environ ['SOME_VAR']
../../../../.virtualenvs/pytest-issue-demo-5A-IlS7_/lib/python3.7/os.py:678:在 getitem
中 从None引发KeyError(key)
E KeyError:'SOME_VAR'
所以似乎没有打通os.environ
的电话。尝试尝试一下,我可能无法修补它。
我的副本可在https://github.com/jamiekt/pytest-issue-demo上找到。希望有人来看看并告诉我如何将呼叫打到os.environ
以便我可以成功运行测试。
它使用pipenv创建一个virtualenv。假设pipenv和make已安装运行
git clone git@github.com:jamiekt/pytest-issue-demo.git
cd pytest-issue-demo
make init test
应该运行测试。
答案 0 :(得分:1)
对os.environ
的调用是该函数的参数列表的一部分,而不是其函数体。这样,表达式os.environ["SOME_VAR"]
会在模块加载时立即求值-事后无法修补,因为导入时会立即发生错误!
这是一种不良的设计模式,应避免使用-函数参数的默认值应限于没有副作用的简单表达式。但是,如果您无法更改此代码,则解决此问题的最简单方法可能是在加载模块时修改“真实” os.environ
:
try:
os.environ["SOME_VAR"] = "qwerty"
from widget import Widget
finally:
del os.environ["SOME_VAR"]
(如果您希望已经设置了环境变量,则在保存和恢复其状态时需要多加注意。)