Как собирать статистику по pytest-прогонам в Test IT

от автора

Как известно, основной проблемой в тестировании является отчетность по прогонам. Некоторые компании собирают данные в отдельном хранилище. Вместо того, чтобы вручную организовывать хранение, было решено сохранять их в Test IT. Такие данные как: исход, время выполнения и количество автоматизированных кейсов позволяют разделить тесты на выборки и дать оценку покрытия автотестами.

Это практично, поскольку в Test IT всё сделали до нас и не придется заново изобретать велосипед. Объединив Test IT и pytest мы сможем выборочно запускать авто тесты. В итоге должна получиться мастер система, из которой будут запускаться тестовые выборки и собираться статистика.

Несмотря на то, что существует множество СУТ (Allure TestOps, TestLink и т.п.), решили остановится на Test IT, поскольку это быстро растущий проект по доступной цене с поддержкой на русском языке, а лицензия на TestRail уже закончилась.

Техническое задание

В рамках задачи следует:

  • Настроить проект в Test IT
  • Настроить прохождение pytest-тестов в GitLab CI
  • Написать плагин для pytest который:
    • создает автоматизированный кейс в Test IT
    • связывает автоматизированный и ручной кейс
    • запускает только те автоматизированные кейсы, которые были выбраны в прогоне
    • отмечает результаты в режиме реального времени

Замечания

Реализация

1. Создание и связывание автоматизированных кейсов в Test IT

В Test IT существует два вида кейсов: ручной и автоматизированный

Для того чтобы в прогоне появилась кнопка Launch Autotests автоматизированный кейс должны быть создан и привязан к ручному

В таком случае напротив ручного кейса появится символ ракеты

Создание и связывание автоматизированного кейса происходит через endpoint AutoTests, в который следует передать два параметра:

  • testit_case_title — название автоматизированного кейса;
  • testit_case_id — идентификатор ручного кейса для привязки.

@pytest.mark.testit_case_id(29035) @putest.mark.testit_case_title("Проверка первой успешной загрузки файла") def test_download_first(test_it_configuration):     """         Автотест прилинкованный к ручному тесту     """     from pprint import pprint     pprint(test_it_configuration)     sleep(randint(a=0, b=8))

Для запуска GitLab CI агента через Test IT следует создать WebHook со следующими параметрами:

Параметры для GitLab CI:

  • URL — ссылка на trigger от GIT-проекта;
  • ref — ветка, в которой запускаются тесты;
  • token — токин от GitLab CI триггера.

Параметры для запуска PYTEST:

  • TEST_IT — флаг сообщающий, что тесты запущены из Test IT;
  • TESTIT_URL — ссылка на Test IT;
  • API_KEY — ключ для Test IT Swagger API;
  • PROJECT_ID — идентификатор проекта в котором вы работаете;
  • TEST_IT_MODE — режим работы с Test IT.

TEST_IT_MODE принимает следующие значения:

  • DELETE_AUTOTESTS
  • CREAT_AUTOTESTS
  • LINK_AUTOTESTS
  • RUN

Эти параметры будут переданы в GitLab CI и сохранены в переменных окружения агента

Тесты получают значения из переменных окружения агента при помощи модуля getenv

from os import getenv  class TestItParams:     """         Параметры из Test IT     """     is_test_it = getenv('TEST_IT', 'False').lower().capitalize() == 'True'     mode = getenv('TEST_IT_MODE', 'RUN')     url = getenv('TESTIT_URL', 'http://tmslt-1.video.rt.ru/')     key = getenv('API_KEY', None)     project_id = getenv('PROJECT_ID', None)     run_id = getenv('TEST_RUN_ID', None)     configuration_id = getenv('CONFIG_ID', None) 

Класс TestItParams следует сохранить в объекте session

def pytest_sessionstart(session):     """         SetUP тестовый сессии: собрать env-параметры из TestIT     """      session.test_it = TestItParams 

Для создания автоматизированного кейса во время запуска pytest, нам нужно достать два параметра testit_case_title и testit_case_id.

Эти параметры можно получить из pytest_collection_modifyitems, поскольку он вызывается во время составления списка на запуск.

Для этого напишем plugin в файле conftest.py

def pytest_collection_modifyitems(session, items):     """         Перехват состояния перед публикацией списка кейсов     """      if session.test_it.is_test_it is True:         print('Тесты запущены для TEST_IT')          if 'DELETE_AUTOTESTS' in session.test_it.mode:             delete_all_auto_test_from_project(pytest_session=session)         if 'CREAT_AUTOTESTS' in session.test_it.mode:             create_autotest_in_project(pytest_session=session, pytest_items=items)         if 'LINK_AUTOTESTS' in session.test_it.mode:             link_autotests_to_testcases(pytest_session=session, pytest_items=items)         if 'RUN' in session.test_it.mode:             select_autotest_from_testrun_only(pytest_session=session)     else:         print('\nПроходит штатный запуск')

Функции create_autotest_in_project и link_autotests_to_testcases это обычные API запросы через endpoint AutoTests.

Параметр test_it_mode используется для разделения задач: создание, привязка, удаление или запуск.

2. Выборочный запуск pytest-тестов

При создании тестового плана возникает потребность в запуске только выбранных автоматизированных кейсов.

Поскольку pytest ничего не знает о тестовом плане, то он должен запрашивать его самостоятельно.

Для этого по значению параметра TEST_RUN_ID через endpoint TestRunes мы получаем список тестов в текущем прогоне.

Далее выбираем только те тесты, которые есть в прогоне и удаляем остальные.

def pytest_collection_modifyitems(session, items):     """         Перехват состояния перед публикацией списка кейсов: создание, удаление, линковка, выборка     """      if session.test_it.is_test_it is True:         print('Тесты запущены для TEST_IT')          if 'DELETE_AUTOTESTS' in session.test_it.mode:             delete_all_auto_test_from_project(pytest_session=session)         if 'CREAT_AUTOTESTS' in session.test_it.mode:             create_autotest_in_project(pytest_session=session, pytest_items=items)         if 'LINK_AUTOTESTS' in session.test_it.mode:             link_autotests_to_testcases(pytest_session=session, pytest_items=items)         if 'RUN' in session.test_it.mode:             select_autotest_from_testrun_only(pytest_session=session)     else:         print('\nПроходит штатный запуск')

Фильтрация происходит в объекте session.items в момент составления списка на запуск.

def select_autotest_from_testrun_only(pytest_session):     """         Выбрать для запуска только те кейсы, которые содержатся в тестовом прогоне     """      run_api = TestRunes(pytest_session.test_it.url, pytest_session.test_it.key)     current_test_run = run_api.get_testrun_by_id(pytest_session.test_it.run_id)      external_ids = []     for case in current_test_run['testResults']:         if case['startedOn'] is None:             external_ids.append((case['autoTest']['externalId'],                                  case['configuration']))      edited_session_items = []     for case in pytest_session.items:         for external_id in external_ids:             if case.name in external_id[0]:                 case.test_it_configuration = external_id[1]                 edited_session_items.append(case)     pytest_session.items = edited_session_items 

3. Возврат результата прохождения pytest-тестов

Каждый автоматизированный кейс должен получать результат прохождения в режиме реального времени а не постфактум.

Для возвращения статуса в реальном времени нам следует воспользоваться хуком pytest_runtest_makereport с декоратором @pytest.hookimpl(hookwrapper=True).

Он позволяет перехватывать выполнение ОДНОГО теста ДО и ПОСЛЕ прохождения.

@pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item):     """         Перехватывает состояние каждого теста во время: setup и done     """      outcome = yield      if 'RUN' in item.session.test_it.mode:         provide_test_results_into_run(pytest_session=item.session,                                       pytest_outcome=outcome,                                       pytest_item=item) 

Этот хук возвращает объект outcome, в котором содержится информация о прогоне текущего теста.

Передача результатов прогона в Test IT происходит через endpoint TestRunes.

def provide_test_results_into_run(pytest_session, pytest_outcome, pytest_item):     """         Предоставить результат выполнения теста в TestIT     """     test_run_api = TestRunes(pytest_session.test_it.url, pytest_session.test_it.key)     res = pytest_outcome.get_result()     if res.when == "call":         autotest_id = pytest_item.name         outcome = res.outcome         duration = res.duration         message = ''         traceback = ''          if res.outcome == 'failed':             message = res.longrepr.reprcrash.message             traceback = res.longreprtext          test_run_api.set_auto_test_results_for_test_run(run_id=pytest_session.test_it.run_id,                                                         autoTestExternalId=autotest_id,                                                         outcome=humanize(outcome),                                                         message=message,                                                         traces=traceback,                                                         duration=duration,                                                         configurationId=pytest_item.test_it_configuration['id']) 

Вывод

Объединив Test IT и pytest мы собрали мастер систему которая умеет:

  • запускать автотесты в GitLab CI;
  • получать результат в режиме реального времени;
  • собирать статистику по запускам;
  • запускать выборки тестов.

Test IT имеет красивый интерфейс, предоставляющий кольцевые-диаграммы, различные таблицы и графики. Можно узнать, в каком прогоне упал конкретный тест и сколько времени он выполнялся.

Демонстрация

Ссылки


ссылка на оригинал статьи https://habr.com/ru/company/rostelecom/blog/695814/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *