Эффективный запуск автотестов в GitLab CI/CD с Python

Введение

В этой статье я хочу поделиться современным подходом к запуску автотестов, который значительно ускоряет процесс тестирования за счет параллельного выполнения тестов в изолированных контейнерах.

Подготовка окружения

Установка необходимых компонентов

  1. Java 8+ - требуется для работы Allure
  2. Node.js - скачать с официального сайта
  3. Allure Commandline:

npm install -g allure-commandline --save-dev

Просмотр отчетов локально

allure serve ./ --host localhost --port 8080

Создание Docker-образа

DockerFile:

FROM python:3.11-bookworm ARG allure_ver=2.21.0 ARG allure_dir=/allure-$allure_ver RUN apt-get update && apt-get install default-jre -y RUN wget --no-check-certificate https://github.com/allure-framework/allure2/releases/download/2.21.0/allure-2.21.0.tgz \ && tar -xf allure-2.21.0.tgz \ && rm -f allure-2.21.0.tgz COPY allure-plugins/links-plugin $allure_dir/plugins/links-plugin COPY allure-plugins/linter-plugin $allure_dir/plugins/linter-plugin COPY allure-plugins/custom-logo-plugin/static/custom-logo.svg $allure_dir/plugins/custom-logo-plugin/static COPY allure-plugins/allure.yml $allure_dir/config ADD /requirements.txt / ENV PATH="${PATH}:/allure-2.21.0/bin" RUN pip install --upgrade pip RUN pip install -r /requirements.txt RUN apt-get update RUN apt-get install -y iputils-ping RUN apt-get update && apt-get install -y wget unzip python3-pip iputils-ping CMD /bin/sh

requirements.txt (основные зависимости)

pytest==8.3.4 aiofiles==23.2.1 allure-pytest==2.13.5 allure-python-commons==2.13.5 loguru==0.7.2 lxml==4.9.3 nest-asyncio==1.5.8 paramiko==3.4.0 playwright==1.38.0 playwright-har-tracer==0.3.2 pydantic==2.10.1 pydantic_core==2.27.1 pytest-base-url==2.1.0 pytest-dependency==0.5.1 pytest-forked==1.6.0 pytest-order==1.1.0 pytest-playwright==0.7.0 pytest-xdist==2.5.0 pytest-asyncio==0.25.3 pytest-random-order==1.1.1 pytest-tagging==1.6.0 pytest-timestamper==0.0.10 pytest-rerunfailures==10.2 python-dateutil==2.8.2 python-slugify==8.0.1 pytest-timeout pyvmomi==8.0.2.0.1 python-dotenv==1.0.1 black==25.1.0 pylint==3.3.7 pylint-gitlab==2.0.1 setuptools-rust==1.11.1

Сборка и публикация образа

docker build -t <your-dockerhub>/python-allure . docker push <your-dockerhub>/python-allure

Настройка GitLab CI/CD

gitlab-ci.yml:

image: <ваш ник в DockerHub>/python-allure:latest variables: NUMBER_OF_THREADS: 1 NUMBER_OF_RERUNS: 1 STAND: $STAND GIT_SUBMODULE_STRATEGY: none stages: - generate-autotests - trigger-autotests - pylint - tests pylint: stage: pylint tags: - gitlab-mini except: - schedules before_script: - mkdir -p lint/badges script: - pylint --exit-zero --output-format=text $(find -type f -name "*.py" ! -path ".") | tee pylint.txt - sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' pylint.txt > lint/badges/$CI_JOB_NAME.score - pylint --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter $(find -type f -name "*.py" ! -path "/") > codeclimate.json - pylint --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter $(find -type f -name "*.py" ! -path "/") > lint/index.html - cp codeclimate.json lint/ artifacts: expire_in: 3 days paths: - lint reports: codequality: codeclimate.json when: always generate-autotests: tags: - gitlab-mini stage: generate-autotests script: - | cat > $CI_PROJECT_DIR/generated-config.yml << EOF stages: - tests - deploy allure-report-publisher: image: <ваш ник в DockerHub>/python-allure:latest stage: deploy tags: - gitlab-mini script: - allure generate ./allure-results --output ./allure-reports artifacts: expire_in: 1 days when: always paths: - ./allure-results .test_template: &test_template image: <ваш ник в DockerHub>/python-allure:latest before_script: - mkdir -p ./allure-results artifacts: expire_in: 1 days when: always paths: - ./allure-results allow_failure: true tags: - gitlab-mini stage: tests when: always script: - py.test -v ./tests/\$SECTION/\$ENDPOINT/\$METHOD/\$CHECK_TYPE/\$AUTOTEST --alluredir=./allure-results $PYTEST_KEY EOF - cd tests - |+ for section in `ls`; do for endpoint in `cd $section; ls`; do for method in `cd $section; cd $endpoint; ls`; do for check_type in `cd $section; cd $endpoint; cd $method; ls`; do for autotest in `cd $section; cd $endpoint; cd $method; cd $check_type; ls`; do echo -en "$section-$endpoint-$method-$check_type-$autotest:\n extends: .test_template\n variables:\n SECTION: ${section}\n ENDPOINT: ${endpoint}\n METHOD: ${method}\n CHECK_TYPE: ${check_type}\n AUTOTEST: ${autotest}\n"; done; done; done; done; done >> $CI_PROJECT_DIR/generated-config.yml - cat $CI_PROJECT_DIR/generated-config.yml artifacts: paths: - generated-config.yml only: - schedules test:ui_tests: tags: - gitlab-mini stage: tests script: - echo ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} - python3 -m pytest -v ./tests --tags ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} -n ${NUMBER_OF_THREADS} --reruns ${NUMBER_OF_RERUNS} --alluredir=./allure-results $PYTEST_KEY rules: - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == "QA-0" when: never - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^QA-\d+/ && $CI_PIPELINE_SOURCE == "merge_request_event"' when: always allow_failure: false trigger-autotests: stage: trigger-autotests needs: - generate-autotests trigger: include: - artifact: generated-config.yml job: generate-autotests strategy: depend only: - schedules

Ключевые преимущества подхода

  1. Параллельное выполнение - каждый тест запускается в отдельном контейнере
  2. Масштабируемость - легко увеличить количество параллельных тестов
  3. Изолированность - проблемы в одном тесте не влияют на другие
  4. Гибкость - можно запускать как отдельные тесты, так и группы

Советы по оптимизации

  1. Используйте кеширование зависимостей в CI/CD
  2. Оптимизируйте Docker-образ (многослойная сборка)
  3. Настройте разумное количество параллельных задач исходя из ресурсов runner'ов
  4. Используйте теги для группировки тестов

Перед использованием вам нужно:

1. Указать свой тег раннера который будет исполнять наш сценарий, в нашем случае это gitlab-mini, у вас он будет другим, для этого обратитесь к девопсам

2. Заменить QA-(названия веток для работы сценария, чуть ниже описано что да как) на ваши названия веток которые вы используете

3. Указать свой ник в образе DockerHub

4. Изменить путь до автотестов(если надо)

В нашем случае это: /tests/users_api/create_user/post/positive/create_user.py(пример)

Где:

SECTION - секция API

ENDPOINT - обозначение API метода

METHOD - сам метода | POST/DELETE/GET и т.д

CHECK_TYPE - тип сценария positive/negative

AUTOTEST - сам файл с автотестом

Вы можете изменить уровень директорий на ваше усмотрение

Разберем сценарий gitlab-ci.yml, он не так сложен:

1. У нас есть 3 формата запуска:

1) Запуск pylint(линтер для анализа кода), происходит при каждом мерже изменений

2) Общий запуск всех автотестов(только при запуске через Pipelines -> Schedules)

3) Запуск автотеста который происходит при появлений в Gitlab новой ветки с названием QA-*(не учитывается QA-0, он для общих изменений), в нашем случае QA- это тег в системе Jira, вы можете использовать любой другой тег

2. При общем запуске всех автотестов наш сценарий выше генерирует новый файл для запуска автотестов(generated-config.yml) который и запускает все автотесты каждый в отдельном контейнере

3. В конце у нас имеется шаг allure-report-publisher который сохраняет артефакты с результатами запуска автотестов(allure-results), чтобы узнать результат прогона автотестов скачиваем артефакт, распаковываем, переходим в директорию allure-results, открываем в этой директорий командную строку и вводим команду: allure serve ./

Копируем файл gitlab-ci.yml выше, сохраняем проект, создаем в Pipelines -> Schedules -> новый триггер для запуска автотестов, настраиваем под себя, сохраняем, запускаем, наслаждаемся результатом!

Если у вас возникнут проблемы, пишите мне на почту - egceska@gmail.com

Постараюсь помочь

Начать дискуссию