Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Как известно, основной проблемой в тестировании является отчетность по прогонам. Некоторые компании собирают данные в отдельном хранилище. Вместо того, чтобы вручную организовывать хранение, было решено сохранять их в Test IT
. Такие данные как: исход, время выполнения и количество автоматизированных кейсов позволяют разделить тесты на выборки и дать оценку покрытия автотестами.
Это практично, поскольку в Test IT
всё сделали до нас и не придется заново изобретать велосипед. Объединив Test IT
и pytest
мы сможем выборочно запускать авто тесты. В итоге должна получиться мастер система, из которой будут запускаться тестовые выборки и собираться статистика.
Несмотря на то, что существует множество СУП (Allure TestOps
, TestLink
и т.п.), решили остановится на Test IT
, поскольку это быстро растущий проект по доступной цене с поддержкой на русском языке, а лицензия на TestRail
уже закончилась.
Техническое задание
В рамках задачи следует:
- Настроить проект в
Test IT
- Настроить прохождение pytest-тестов в
GitLab CI
- Написать плагин для
pytest
который:
- создает автоматизированный кейс в
Test IT
- связывает автоматизированный и ручной кейс
- запускает только те автоматизированные кейсы, которые были выбраны в прогоне
- отмечает результаты в режиме реального времени
- создает автоматизированный кейс в
Замечания
- Для работы с Test IT Swagger API следует создать
API-secret-key
Реализация
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 = eval(getenv('TEST_IT', 'False'))
mode = getenv('TEST_IT_MODE', 'REGULAR')
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 имеет красивый интерфейс, предоставляющий кольцевые-диаграммы, различные таблицы и графики. Можно узнать, в каком прогоне упал конкретный тест и сколько времени он выполнялся.
Демонстрация
Ссылки
- Александр Волков — Pytest Plugins: Как расширить функционал тестового фреймворка через плагины
- Test IT Swagger API
- pytest