Есть ли способ контролировать, как pytest-xdist выполняет тесты параллельно?
У меня есть следующий макет каталога:
runner.py
lib/
tests/
testsuite1/
testsuite1.py
testsuite2/
testsuite2.py
testsuite3/
testsuite3.py
testsuite4/
testsuite4.py
Формат модулей testsuite*.py выглядит следующим образом:
импортный тест классные тесты def setup_class(self): '''сделать некоторые настройки''' # Выполните некоторые настройки здесь def teardown_class(self): '''сделай демонстрант''' # Сделайте некоторые вещи здесь def test1(self): # Сделайте некоторые вещи, связанные с test1 def test2(self): # Сделайте некоторые вещи, связанные с test2 .... .... .... def test40(self): # Сделайте некоторые вещи, связанные с test40 if __name__=='__main()__' pytest.main(Args=[os.path.abspath(__ FILE__)])
Проблема, с которой я столкнулся, заключается в том, что я хотел бы выполнять тестовые наборы параллельно, то есть я хочу, чтобы testsuite1, testsuite2, testsuite3 и testsuite4 запускал выполнение параллельно, но отдельные тесты в пределах тестовых наборов должны выполняться последовательно.
Когда я использую плагин "xdist" из py.test и запускаю тесты с помощью "py.test -n 4", py.test собирает все тесты и случайным образом балансирует нагрузку тестов среди 4 рабочих. Это приводит к тому, что метод "setup_class" выполняется каждый раз при каждом тесте в модуле "testsuitex.py" (что противоречит моей цели. Я хочу, чтобы setup_class выполнялся только один раз для каждого класса, а тесты выполнялись последовательно после этого).
По сути, я хочу, чтобы исполнение выглядело так:
worker1: выполняет все тесты в testsuite1.py поочередно worker2: выполняет все тесты в testsuite2.py поочередно worker3: выполняет все тесты в testsuite3.py поочередно worker4: выполняет все тесты в testsuite4.py поочередно
в то время как worker1, worker2, worker3 and worker4
все выполняются параллельно.
Есть ли способ достичь этого в рамках pytest-xidst?
Единственный вариант, о котором я могу подумать, - запустить разные процессы для индивидуального выполнения каждого набора тестов в runner.py:
def test_execute_func (testsuite_path): subprocess.process ('py.test% s'% testsuite_path) if __name __ == '__ main__': # Собрать все имена testsuite для каждого testsuite: multiprocessing.Process(test_execute_func,(testsuite_path)
6 ответов
Вы можете использовать --dist=loadscope
сгруппировать все тесты в одном классе. Вот документ от Pytest-XDist на Pypi
По умолчанию опция -n отправляет ожидающие тесты любому работнику, который доступен, без какого-либо гарантированного заказа, но вы можете управлять этим с помощью этих опций:
--dist=loadscope
: тесты будут сгруппированы по модулям для функций тестирования и по классам для методов тестирования, затем каждая группа будет отправлена доступному работнику, гарантируя, что все тесты в группе выполняются в одном и том же процессе. Это может быть полезно, если у вас есть дорогие приборы уровня модуля или класса. В настоящее время группировки не могут быть настроены, так как группировка по классу имеет приоритет над группировкой по модулю. Эта функция была добавлена в версии 1.19.
--dist=loadfile
: тесты будут сгруппированы по имени файла, а затем будут отправлены доступному работнику, гарантируя, что все тесты в группе выполняются на одном и том же работнике. Эта функция была добавлена в версии 1.21.
Да, есть такие способы, доступные опции для версии xdist 1.28.0
это следующие:
--dist=each
: Отправляет все тесты на все узлы, поэтому каждый тест выполняется на каждом узле.--dist=load
: Распределяет тесты, собранные по всем узлам, поэтому каждый тест запускается только один раз. Все узлы собирают и отправляют набор тестов, и когда все наборы (наборов тестов) получены, это подтверждается, что они являются идентичными наборами. Затем коллекция разделяется на куски, а куски отправляются на узлы для выполнения.--dist=loadscope
Распределяет тесты, собранные по всем узлам, поэтому каждый тест запускается только один раз. Все узлы собирают и отправляют список тестов, и когда все коллекции получены, подтверждается, что они являются идентичными коллекциями. Затем коллекция разделяется на рабочие единицы, сгруппированные по областям тестирования, и эти рабочие единицы передаются на узлы.--dist=loadfile
Распределяет тесты, собранные по всем узлам, поэтому каждый тест запускается только один раз. Все узлы собирают и отправляют список тестов, и когда все коллекции получены, подтверждается, что они являются идентичными коллекциями. Затем коллекция разделяется на рабочие единицы, сгруппированные по тестовому файлу, и эти рабочие единицы передаются на узлы.
Если вам нужна дополнительная информация, я рекомендую вам перейти непосредственно к фактической реализации планировщиков и проверить, как осуществляется распределение.
С pytest-xdist в настоящее время нет какого-либо дистрибутива "для каждого файла" или "для каждого теста". На самом деле, если распределение по каждому файлу (например, тесты в файле будут выполняться не более чем одним работником за раз) уже помогло бы вашему варианту использования, я призываю вас подать проблему с функцией отслеживания проблем pytest по адресу https://bitbucket.org/hpk42/pytest/issues?status=new&status=open и приведите ссылку на хорошее объяснение здесь.
веселит, Хольгер
Pytest _mproc ( https://nak.github.io/pytest_mproc_docs/index.html) предоставляет "групповой" декоратор, который позволяет вам группировать тесты вместе для последовательного выполнения. Он также имеет более быстрое время запуска при работе с большим количеством ядер, чем xdist, и обеспечивает "глобальную" возможность тестирования.
Имея тестовые наборы в каталоге, как в вопросе, вы можете запускать их параллельно с помощью:
pytest -n=$(ls **/test*py | wc -l) --dist=loadfile
Если у вас есть файлы набора тестов в одном каталоге, просто
pytest -n=$(ls test*py | wc -l) --dist=loadfile
В случае появления нового файла пакета он автоматически включит новый тестовый файл и добавит для него дополнительного рабочего.
Также стоит отметить, что эта проблема на github pytest-xdist касается варианта использования, о котором я думаю, вы здесь спрашиваете.
Поскольку проблема еще не решена (несмотря на то, что она была открыта в 2015 году), я просто исправил работоспособное решение для моего конкретного случая. В свой conftest.py я добавил этот кусок кода:
import xdist.scheduler as xdist_scheduler
def _split_scope(self, nodeid):
return nodeid.rsplit("[", 1)[-1]
xdist_scheduler.loadscope.LoadScopeScheduling._split_scope = _split_scope
По сути, он просто перезаписывает функцию _split_scope из xdist, чтобы разбить группы по идентификатору узла, а не по типу файла. У меня это сработало, но я не могу гарантировать надежность, поскольку мы обезьяны исправляем некоторый обычно внутренний код; Используйте на свой риск.