Значение Monkeypatch setenv сохраняется во всех тестовых примерах в python unittest

#python-3.x #python-unittest #monkeypatching

#python-3.x #python-unittest #monkeypatching

Вопрос:

Я должен установить разные переменные среды для своих тестовых примеров.

Я предполагал, что после завершения тестового примера monkeypatch удалит переменные env из 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()
 

Вывод:

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

OK
 

Ответ №1:

Чтобы удалить переменную env, установленную monkeypatch модулем, кажется, вам нужно вызвать delenv метод. Вы можете вызвать это delenv после того, как закончите настройку и тестирование переменной env с помощью setenv метода, но я думаю tearDown , что было бы правильным местом для размещения этого вызова delenv.

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

Я не тестировал код, однако должен дать вам достаточное представление о том, что нужно сделать.

РЕДАКТИРОВАТЬ: улучшен код для более эффективного использования setup * tearDown. test_2 должно вызвать ошибку ОС, поскольку переменная env была удалена

 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()
 

Приветствия!

Ответ №2:

Это немного расширяет (правильный) ответ, данный @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()       

 

Очистка в этом случае выполняется при выходе из диспетчера контекста.