feat: test data generators (ФЛК) and static fixtures structure
Добавлена инфраструктура для тестовых данных: tests/testdata/generators.py — генераторы случайных данных по ФЛК: - Раздел 'Животное': gen_animal_name, gen_birth_date - Раздел 'Маркировка': gen_microchip (ISO 11784/85), gen_tattoo - Раздел 'Владелец': gen_owner_full_name, gen_owner_phone, gen_owner_email Каждая функция содержит описание ФЛК правил и пример вывода. Файл содержит подробное руководство по добавлению новых генераторов. tests/01_vetdept/fixtures/ — папка для статических артефактов роли: fixtures/images/ ← фото животных fixtures/docs/ ← PDF, сертификаты tests/01_vetdept/conftest.py — добавлена фикстура fixtures_dir (Path), возвращает путь к папке артефактов для использования в тестах. requirements.txt — добавлен faker (генерация русскоязычных данных)
This commit is contained in:
@ -4,4 +4,5 @@ pytest-playwright
|
|||||||
pytest-xdist
|
pytest-xdist
|
||||||
pytest-html
|
pytest-html
|
||||||
pytest-dependency
|
pytest-dependency
|
||||||
|
faker
|
||||||
python-dotenv
|
python-dotenv
|
||||||
@ -1,4 +1,40 @@
|
|||||||
|
# pyrefly: ignore [missing-import]
|
||||||
import pytest
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Пути к статическим артефактам роли (фото, документы, файлы)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def fixtures_dir() -> Path:
|
||||||
|
"""
|
||||||
|
Путь к папке со статическими артефактами роли vetdept.
|
||||||
|
Структура папки:
|
||||||
|
fixtures/
|
||||||
|
├── images/ ← фотографии животных, документы-сканы
|
||||||
|
└── docs/ ← PDF, сертификаты и прочие документы
|
||||||
|
|
||||||
|
Используй как базовый путь для других фикстур-артефактов:
|
||||||
|
def test_s02_upload(self, browser_page, fixtures_dir):
|
||||||
|
photo = fixtures_dir / "images" / "cat_photo.jpg"
|
||||||
|
browser_page.set_input_files("input[type=file]", str(photo))
|
||||||
|
"""
|
||||||
|
return Path(__file__).parent / "fixtures"
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Готовые фикстуры для конкретных артефактов
|
||||||
|
# Добавляй новые по мере появления новых файлов в папке fixtures/
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Пример: раскомментируй и адаптируй когда нужен конкретный файл
|
||||||
|
#
|
||||||
|
# @pytest.fixture(scope="session")
|
||||||
|
# def cat_photo(fixtures_dir) -> Path:
|
||||||
|
# """Фотография кошки для теста загрузки фото животного."""
|
||||||
|
# return fixtures_dir / "images" / "cat_photo.jpg"
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
1
tests/01_vetdept/fixtures/docs/.gitkeep
Normal file
1
tests/01_vetdept/fixtures/docs/.gitkeep
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Эта папка хранит PDF, сертификаты и прочие документы для тестов загрузки файлов.
|
||||||
2
tests/01_vetdept/fixtures/images/.gitkeep
Normal file
2
tests/01_vetdept/fixtures/images/.gitkeep
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Эта папка хранит фотографии животных и другие изображения для тестов.
|
||||||
|
# Добавляй реальные файлы сюда и создавай фикстуры в ../conftest.py
|
||||||
3
tests/testdata/__init__.py
vendored
Normal file
3
tests/testdata/__init__.py
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Пакет тестовых данных
|
||||||
|
# Содержит генераторы случайных данных по правилам ФЛК
|
||||||
|
from .generators import * # noqa: F401, F403
|
||||||
197
tests/testdata/generators.py
vendored
Normal file
197
tests/testdata/generators.py
vendored
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
"""
|
||||||
|
Генераторы тестовых данных по правилам ФЛК (Форматно-Логический Контроль).
|
||||||
|
|
||||||
|
=============================================================================
|
||||||
|
КАК ДОБАВИТЬ НОВЫЙ ГЕНЕРАТОР
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
1. Определи раздел (секцию) к которому относится данное поле.
|
||||||
|
Разделы обозначены комментариями: # === РАЗДЕЛ: ... ===
|
||||||
|
|
||||||
|
2. Если нужного раздела нет — добавь новый в конце файла по шаблону:
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# === РАЗДЕЛ: Название раздела ===
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
3. Напиши функцию-генератор в нужном разделе:
|
||||||
|
|
||||||
|
def gen_<сущность>_<поле>(<параметры>) -> <тип>:
|
||||||
|
\"\"\"
|
||||||
|
Краткое описание что генерирует функция.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Правило 1 (например: только цифры)
|
||||||
|
- Правило 2 (например: длина ровно 15 символов)
|
||||||
|
- Правило 3 (например: начинается с '643')
|
||||||
|
|
||||||
|
Аргументы:
|
||||||
|
param1 — описание параметра и его диапазон
|
||||||
|
|
||||||
|
Пример вывода: '643094100123456'
|
||||||
|
\"\"\"
|
||||||
|
...
|
||||||
|
|
||||||
|
4. Если функция использует Faker — используй уже созданный экземпляр `fake`
|
||||||
|
(не создавай новые экземпляры в каждой функции).
|
||||||
|
|
||||||
|
5. Если данные статические (например, список имён) — помести их как константу
|
||||||
|
перед функцией с именем _DATA_<НАЗНАЧЕНИЕ>.
|
||||||
|
|
||||||
|
=============================================================================
|
||||||
|
ПРИМЕР ИСПОЛЬЗОВАНИЯ В ТЕСТЕ
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
from tests.testdata.generators import gen_microchip, gen_animal_name
|
||||||
|
|
||||||
|
class TestBP02RegisterAnimal:
|
||||||
|
def test_s01_fill_form(self, browser_page, bp_state):
|
||||||
|
name = gen_animal_name()
|
||||||
|
microchip = gen_microchip()
|
||||||
|
|
||||||
|
browser_page.fill("#animal-name", name)
|
||||||
|
browser_page.fill("#microchip", microchip)
|
||||||
|
|
||||||
|
bp_state["animal_name"] = name # передаём следующему шагу
|
||||||
|
bp_state["microchip"] = microchip
|
||||||
|
|
||||||
|
=============================================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from datetime import date, timedelta
|
||||||
|
from faker import Faker
|
||||||
|
|
||||||
|
# Единственный экземпляр Faker на весь модуль — не создавай новые в функциях
|
||||||
|
fake = Faker("ru_RU")
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# === РАЗДЕЛ: Животное ===
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
_DATA_ANIMAL_NAMES = [
|
||||||
|
"Мурка", "Барсик", "Шарик", "Рекс", "Симба",
|
||||||
|
"Дружок", "Звезда", "Кличко", "Жорик", "Буся",
|
||||||
|
"Тузик", "Маркиз", "Пуговка", "Снежок", "Рыжик",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def gen_animal_name() -> str:
|
||||||
|
"""
|
||||||
|
Кличка животного.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Только кириллица
|
||||||
|
- Первая буква заглавная
|
||||||
|
- От 2 до 20 символов
|
||||||
|
|
||||||
|
Пример вывода: 'Мурка'
|
||||||
|
"""
|
||||||
|
return random.choice(_DATA_ANIMAL_NAMES)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_birth_date(min_years: int = 0, max_years: int = 20) -> str:
|
||||||
|
"""
|
||||||
|
Дата рождения животного.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Не позднее сегодняшнего дня
|
||||||
|
- Не ранее max_years лет назад
|
||||||
|
- Формат: ДД.ММ.ГГГГ
|
||||||
|
|
||||||
|
Аргументы:
|
||||||
|
min_years — минимальный возраст в годах (по умолчанию 0 = только что рождён)
|
||||||
|
max_years — максимальный возраст в годах (по умолчанию 20)
|
||||||
|
|
||||||
|
Пример вывода: '15.03.2021'
|
||||||
|
"""
|
||||||
|
min_days = min_years * 365
|
||||||
|
max_days = max_years * 365
|
||||||
|
delta = random.randint(min_days, max_days)
|
||||||
|
birth = date.today() - timedelta(days=delta)
|
||||||
|
return birth.strftime("%d.%m.%Y")
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# === РАЗДЕЛ: Маркировка животного ===
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
def gen_microchip() -> str:
|
||||||
|
"""
|
||||||
|
Номер микрочипа.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Ровно 15 цифр
|
||||||
|
- Стандарт ISO 11784/85
|
||||||
|
- Первые 3 цифры — код страны (643 = Россия) [опционально]
|
||||||
|
|
||||||
|
Пример вывода: '643094100123456'
|
||||||
|
"""
|
||||||
|
return "".join(str(random.randint(0, 9)) for _ in range(15))
|
||||||
|
|
||||||
|
|
||||||
|
def gen_tattoo() -> str:
|
||||||
|
"""
|
||||||
|
Номер клейма (тату-маркировка).
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- 2 заглавные латинские буквы
|
||||||
|
- 4 цифры
|
||||||
|
- Итого 6 символов
|
||||||
|
|
||||||
|
Пример вывода: 'AB1234'
|
||||||
|
"""
|
||||||
|
letters = "".join(random.choices(string.ascii_uppercase, k=2))
|
||||||
|
digits = "".join(str(random.randint(0, 9)) for _ in range(4))
|
||||||
|
return letters + digits
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# === РАЗДЕЛ: Владелец животного ===
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
def gen_owner_full_name() -> str:
|
||||||
|
"""
|
||||||
|
ФИО владельца.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Только кириллица
|
||||||
|
- Формат: Фамилия Имя Отчество
|
||||||
|
|
||||||
|
Пример вывода: 'Иванов Иван Иванович'
|
||||||
|
"""
|
||||||
|
return fake.name()
|
||||||
|
|
||||||
|
|
||||||
|
def gen_owner_phone() -> str:
|
||||||
|
"""
|
||||||
|
Мобильный телефон владельца.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Российский номер
|
||||||
|
- Начинается с +7
|
||||||
|
- Код оператора: 9XX (мобильные)
|
||||||
|
- Формат: +7(9XX)XXX-XX-XX
|
||||||
|
|
||||||
|
Пример вывода: '+7(916)543-21-09'
|
||||||
|
"""
|
||||||
|
code = random.randint(900, 999)
|
||||||
|
part1 = random.randint(100, 999)
|
||||||
|
part2 = random.randint(10, 99)
|
||||||
|
part3 = random.randint(10, 99)
|
||||||
|
return f"+7({code}){part1}-{part2}-{part3}"
|
||||||
|
|
||||||
|
|
||||||
|
def gen_owner_email() -> str:
|
||||||
|
"""
|
||||||
|
Email владельца.
|
||||||
|
|
||||||
|
ФЛК:
|
||||||
|
- Валидный формат email
|
||||||
|
- Латинские символы
|
||||||
|
|
||||||
|
Пример вывода: 'ivanov.ivan@example.com'
|
||||||
|
"""
|
||||||
|
return fake.email()
|
||||||
Reference in New Issue
Block a user