Python 模拟 os.environ 在 class 中使用

Python mock os.environ used inside a class

我正在尝试在 class 中模拟 os.environ,但我就是做不对。这是我的结构:

#file.py
import os

class MyClass():
    connection_url = os.environ['DB']

#some code

这是我的测试(无论如何都是最新的尝试):

#test.py
from unittest import TestCase
from unittest.mock import patch
from file import MyClass

class TestMyClass(TestCase):
    @patch.dict('file.os.environ', {'DB' : 'Dummy' })
    def setUp(self):
         self.class = MyClass()

#some testing

这非常失败,引发了 KeyError 'DB'...有人可以帮助我吗?我是 python 单元测试的新手。我研究了一些博客和 Whosebug,尝试了一些解决方案但无法正确解决。

提前致谢!

这里的问题是 connection_url 在创建 class 时设置(在导入时)。如果你想模拟它,你可以在 使用 之前修补 class 本身的属性:

class TestMyClass(TestCase):
    @patch.object(file.MyClass, 'connection_url', 'Dummy')
    def setUp(self):
        self.instance = MyClass()

您仍然需要在导入时处理潜在的 KeyError —— 即您需要确保您的测试运行程序在您 [=34= 之前的环境中具有虚拟值]import file 否则你必须修改 file.py 中的代码以确保它不会引发 KeyError。这里有一些策略。如果环境中未设置 KeyErrorconnection_url = default_value,您可以只抑制它:

class MyClass():
    connection_url = os.environ.get('DB', default_value)

或者您可以将 connection_url 提取移动到 __init__:

class MyClass():
    def __init__(self):
        connection_url = os.environ['DB']

后面的代码还有一个额外的好处,那就是您的 patch.dict 应该开始工作了。

请注意,如果您选择前两种方法中的任何一种,实例将仅在 setUp 方法期间有补丁 connection_url -- 后续测试不会有补丁。这很可能会成为阻碍,您需要在您拥有的每个测试中创建一个新实例:

class TestMyClass(TestCase):
    @patch.object(file.MyClass, 'connection_url', 'Dummy')
    def test_first_thing(self):
        self.instance = MyClass()
        ...

    @patch.object(file.MyClass, 'connection_url', 'Dummy')
    def test_second_thing(self):
        self.instance = MyClass()
        ...