Есть ли способ контролировать, как 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, чтобы разбить группы по идентификатору узла, а не по типу файла. У меня это сработало, но я не могу гарантировать надежность, поскольку мы обезьяны исправляем некоторый обычно внутренний код; Используйте на свой риск.

Другие вопросы по тегам