使用mock.patch.dict()修补导入类中的os.environ

时间:2019-07-22 21:30:36

标签: python pytest

我想对在其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

应该运行测试。

1 个答案:

答案 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"]

(如果您希望已经设置了环境变量,则在保存和恢复其状态时需要多加注意。)