Перезапустите python (или перезагрузите модули) в тестах py.test
У меня есть пакет (python3), который имеет совершенно другое поведение в зависимости от того, как это init()
ed (возможно, не лучший дизайн, но переписывание не вариант). Модуль может быть только init()
Один раз, второй раз выдает ошибку. Я хочу протестировать этот пакет (оба поведения), используя py.test.
Примечание: природа пакета делает эти два поведения взаимоисключающими, нет никакой возможной причины когда-либо хотеть оба в единственной программе.
У меня есть несколько test_xxx.py
модули в моей тестовой директории. Каждый модуль будет инициализировать пакет так, как ему нужно (используя приспособления). поскольку py.test
запускает интерпретатор python один раз, сбой всех тестовых модулей за один запуск py.test.
Обезьяна-исправление пакета, чтобы позволить второй init()
я не хочу этого делать, поскольку существует внутреннее кэширование и т. д., которое может привести к необъяснимому поведению.
- Можно ли сказать py.test запускать каждый тестовый модуль в отдельном процессе python (таким образом, на него не влияют inits другого тестового модуля)
- Есть ли способ надежно перезагрузить пакет (включая все подчиненные и т. Д.)?
- Есть ли другое решение (я думаю об импорте, а затем об импорте пакета в приспособлении, но это кажется чрезмерным)?
4 ответа
Чтобы перезагрузить модуль, попробуйте использовать reload()
из библиотеки imp
Пример:
from imp import reload
import some_lib
#do something
reload(some_lib)
Кроме того, запуск каждого теста в новом процессе является жизнеспособным, но многопроцессорный код является болезненным для отладки.
пример
import some_test
from multiprocessing import Manager, Process
#create new return value holder, in this case a list
manager = Manager()
return_value = manager.list()
#create new process
process = Process(target=some_test.some_function, args=(arg, return_value))
#execute process
process.start()
#finish and return process
process.join()
#you can now use your return value as if it were a normal list,
#as long as it was assigned in your subprocess
Удалите весь импорт модулей, а также импорт тестов, которые также импортируют ваши модули:
import sys
for key in list(sys.modules.keys()):
if key.startswith("your_package_name") or key.startswith("test"):
del sys.modules[key]
вы можете использовать это как приспособление, настроив на своем
conftest.py
запилить приспособление, используя
@pytest.fixture
декоратор.
Однажды у меня была похожая проблема, правда, довольно плохой дизайн..
@pytest.fixture()
def module_type1():
mod = importlib.import_module('example')
mod._init(10)
yield mod
del sys.modules['example']
@pytest.fixture()
def module_type2():
mod = importlib.import_module('example')
mod._init(20)
yield mod
del sys.modules['example']
def test1(module_type1)
pass
def test2(module_type2)
pass
В примере /init.py было что-то вроде этого
def _init(val):
if 'sample' in globals():
logger.info(f'example already imported, val{sample}' )
else:
globals()['sample'] = val
logger.info(f'importing example with val : {val}')
выход:
importing example with val : 10
importing example with val : 20
Понятия не имею, насколько сложен ваш пакет, но если это просто глобальные переменные, то это, вероятно, поможет.
У меня такая же проблема, и я нашел три решения:
- перезагрузить (some_lib)
- patch SUT, поскольку импортированный метод является ключом и значением в SUT, вы можете исправить SUT. Например, если вы используете f2 из m2 в m1, вы можете пропатчить m1.f2 вместо m2.f2
- import module и используйте module.function.