Небольшое введение в автотестирование бизнес-процессов Гриндаты, с чего начать и как продолжить
Небольшое введение в автотестирование бизнес-процессов Гриндаты, с чего начать и как продолжить
Python, pytest, patchright
У нас довольно сложные бизнес-процессы, с множеством исполнителей, и ручное тестирование сильно затягивает вывод реализованных БП в прод
Появились некоторые наработки по автотестам, которые, к сожалению, с большой вероятностью придётся скоро убрать в стол 😐
В целом, вся информация легко находится в интернетах и gpt отлично в этом помогает, но решил оставить её здесь для коллег, это поможет быстро начать писать автотесты
Используется классический подход к автотестам, PageObject и иже с ними. Стек выбран самый популярный, и достаточно лёгкий для входа. В статье не рассматривается установка питона и пр. Предполагается, что читающий знаком с питоном, виртуальными окружениями venv, системой управления зависимостями pip
В конце статьи мы получим полностью работающий тест авторизации (1) в Гриндату несколькими пользователями разных ролей (Групп доступа), и отчёт о таком тестировании. Тесты предполагают, что пользователи уже созданы
(1) На самом деле - это тесты аутентификации, они проверяют только корректность логина/пароля; определение прав пользователя это следующий шаг, в статье он не рассматривается. Мы лишь проверим, что пользователь после авторизации попадает на свою стартовую страницу
Структура проекта
gd-py-autotests/
├── tests/
│ ├── test_auth.py # Тесты авторизации
│ └── conftest.py # Конфигурация pytest
├── pages/
│ ├── base_page.py # Базовый класс для всех страниц
│ └── login_page.py # Страница авторизации
├── requirements.txt
├── pytest.ini
└── test_data.yaml # Тестовые данные, пользователи
Создание и активация виртуального окружения venv
python -m venv .venv
.venv\Scripts\activate # Windows
. .venv/bin/activate # Linux
Установка pytest, patchright
# можно установить последние версии pytest и patchright,
# и их зависимости следующей командой:
pip install pytest patchright pyyaml
# а можно установить актуальные на момент статьи версии
# всех зависимостей из файла requirements.txt (его содержимое ниже):
pip install -r requirements.txt
requirements.txt
# requirements.txt
colorama==0.4.6
greenlet==3.2.4
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.3
packaging==25.0
patchright==1.55.2
pluggy==1.6.0
pyee==13.0.0
Pygments==2.19.2
pytest==8.4.2
pytest-html==4.1.1
pytest-metadata==3.1.1
PyYAML==6.0.3
typing_extensions==4.15.0
Установка браузеров patchright
patchright install
Эта команда установит основные браузеры (firefox, chtomium) в виртуальное окружение venv
Проверить установку браузеров можно командой
patchright cr https://ya.ru # откроет страницу Яндекс-поиска в chronium
patchright ff https://ya.ru # в firefox
Тестовые данные
В тесте авторизации будут использованы несколько пользователей, которые должны быть созданы в Гриндате; и один пользователь, которого не существует (проверим, что Гриндата не авторизует кого попало). Опишем этих пользователей в файле test_data.yaml
# test_data.yaml
users:
- role: "Менеджер отдела авторизации"
username: "manager"
password: "password"
expected_url_part: "card/666000" # Ожидаем, что попадём на эту страницу после логина
- role: "Руководитель отдела авторизации"
username: "director"
password: "password"
expected_url_part: "card/666001"
- role: "Специалист отдела авторизации"
username: "specialist"
password: "password"
expected_url_part: "card/666002"
- role: "Невалидный пользователь"
username: "invalid_user"
password: "wrong_password"
expected_url_part: "login" # Ожидаем, что останемся на странице логина
Параметры, конфигурация pytest, patchright
Используем только chromium; параметром slow_mo немного замедляем прохождение тестов (если поставить 1000 (1 секунда), это заметно замедлит выполнение тестов, увеличит созерцаемость, повысит осознанность)
# conftest.py
import pytest
from patchright.sync_api import sync_playwright
@pytest.fixture(scope="session")
def browser():
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False,
channel="chrome",
slow_mo=100,
)
yield browser
browser.close()
@pytest.fixture(scope="function")
def page(browser):
page = browser.new_page()
yield page
page.close()
PageObject для страницы авторизации
Пара файлов: pages/base_page.py, pages/login_page.py
# base_page.py, абстрактный класс BaseObject, родитель всех страниц
from patchright.sync_api import Page
class BasePage:
def __init__(self, page: Page):
self.page = page
def goto(self, url: str):
self.page.goto(url)
self.page.wait_for_load_state('networkidle')
def is_element_visible(self, selector: str) -> bool:
return self.page.is_visible(selector)
# login_page.py, класс LoginPage, описывает страницу авторизации Гриндаты
from pages.base_page import BasePage
class LoginPage(BasePage):
def __init__(self, page):
super().__init__(page)
self.username_input = 'input[class="login-input"]'
self.password_input = 'input[class="password-input"]'
self.login_button = 'button:has-text("Войти")' # Предполагается, что используется интерфейс на русском языке
def login(self, username: str, password: str):
self.page.fill(self.username_input, username)
self.page.fill(self.password_input, password)
self.page.click(self.login_button)
def is_login_form_visible(self) -> bool:
return self.is_element_visible(self.username_input)
Тест авторизации
Файл tests/test_auth.py
# test_auth.py
import pytest
import yaml
from pages.login_page import LoginPage
def load_user_data_from_yaml():
"""Читает пользователей из YAML-файла"""
with open("test_data.yaml", "r", encoding="utf-8") as f:
data = yaml.safe_load(f)
# Создаем "красивые" ID для отображения в отчете pytest
return [pytest.param(user, id=user.get('role', 'unknown_role')) for user in data['users']]
class TestAuthentication:
@pytest.mark.parametrize("user_data", load_user_data_from_yaml())
def test_user_login(self, page, user_data):
"""
Тест проверяет авторизацию для пользователей c разными ролями (группами доступа)
"""
login_page = LoginPage(page)
login_page.goto("https://test-ecocultura.local/")
assert login_page.is_login_form_visible()
login_page.login(user_data["username"], user_data["password"])
page.wait_for_timeout(5000) # такие таймауты мы называем злом, но статья не об этом
# https://trofimovdigital.ru/blog/jedi-principles-for-write-ideal-autotests
assert user_data["expected_url_part"] in page.url
That's all folks
# Запуск всех тестов
pytest
# Запуск с подробностями
pytest -v -s
# Запуск конкретного теста
pytest tests/test_auth.py::TestAuthentication::test_user_login
# Запуск тестов, генерация отчёта в формате HTML
pytest --html=report.html --self-contained-html
# Запуск тестов, генерация отчёта в формате JUnit
pytest --junitxml="report.xml"
