Monkeypatch setenv 值在 python 单元测试中跨测试用例持续存在

Monkeypatch setenv value persist across test cases in python unittest

我必须为我的测试用例设置不同的环境变量。

我的假设是一旦测试用例完成,monkeypatch 将从 os.environ 中删除环境变量。但事实并非如此。如何为每个测试设置和恢复环境变量?

这是我使用 monkeypatch 库简化的测试用例代码。

import os
import unittest
import time
from _pytest.monkeypatch import MonkeyPatch

class Test_Monkey_Patch_Env(unittest.TestCase):
    def setUp(self):
        print("Setup")

    def test_1(self):
        monkeypatch = MonkeyPatch()
        monkeypatch.setenv("TESTVAR1", "This env value is persistent")

    def test_2(self):
        # I was expected the env TESTVAR1 set in test_1 using monkeypatch
        # should not persist across test cases. But it is.
        print(os.environ["TESTVAR1"]) 

    def tearDown(self):
        print("tearDown")
            

if __name__ == '__main__':
    unittest.main()

Output:

Setup
tearDown
.Setup
This env value is persistent
tearDown
.
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

要删除由 monkeypatch 模块设置的环境变量,似乎必须调用 delenv 方法。 在使用 setenv 方法完成设置和测试环境变量后,您可以调用此 delenv,但我认为 tearDown 是放置 delenv 调用的正确位置。

def tearDown(self):
    print("tearDown")
    monkeypatch.delenv('TESTVAR1', raising=False)

我还没有测试过代码,但是应该会让你知道需要做什么。

编辑:改进代码以更有效地使用 setup * tearDown。 test_2 应该引发 OS 错误,因为环境变量已被删除

import os
import unittest
import time
from _pytest.monkeypatch import MonkeyPatch

class Test_Monkey_Patch_Env(unittest.TestCase):
    def setUp(self):
        self.monkeypatch = MonkeyPatch()
        print("Setup")

    def test_1(self):
        self.monkeypatch.setenv("TESTVAR1", "This env value is persistent")

    def test_2(self):
        # I was expected the env TESTVAR1 set in test_1 using monkeypatch
        # should not persist across test cases. But it is.
        print(os.environ["TESTVAR1"])   # Should raise OS error

    def tearDown(self):
        print("tearDown")
        self.monkeypatch.delenv("TESTVAR1", raising=False)
            

if __name__ == '__main__':
    unittest.main()

干杯!

这对@MaNKuR 给出的(正确)答案进行了一些扩展。

它不能按预期工作的原因是在 pytest 中,它不是设计为以这种方式使用的 - 而是使用 monkeypatch 夹具,它在离开测试范围时进行清理。要在 unittest 中进行清理,您可以在 tearDown 中进行清理,如答案所示 - 尽管我会为此使用不太具体的 undo

from _pytest.monkeypatch import MonkeyPatch

class Test_Monkey_Patch_Env(unittest.TestCase):
    def setUp(self):
        self.monkeypatch = MonkeyPatch()

    def tearDown(self):
        self.monkeypatch.undo()

这会还原使用 MonkeyPatch 实例所做的任何更改,而不仅仅是上面显示的特定 setenv 调用,因此更安全。

此外,还可以使用 MonkeyPatch 作为上下文管理器。如果您只想在一个或几个测试中使用它,这会派上用场。在这种情况下你可以这样写:

...
    def test_1(self):
        with MonkeyPatch() as mp:
            mp.setenv("TESTVAR1", "This env value is not persistent")
            do_something()       

这种情况下的清理是在退出上下文管理器时完成的。