docs: GUIDE.md — полный гайд по созданию автотестов с нуля

This commit is contained in:
Maksim Totmin 2026-06-23 12:37:48 +07:00
parent 3f7bd3861b
commit 4867e4cebc
2 changed files with 307 additions and 0 deletions

303
GUIDE.md Normal file
View File

@ -0,0 +1,303 @@
# Как создать автотесты для другого проекта
Этот гайд описывает полный цикл создания автотестов для SEE и SMC на любом проекте — от первого запуска до полного набора asserts.
## Архитектура тестов
Тесты **универсальные**: не содержат хардкода имён моделей. Всё привязывается динамически:
| Компонент | Где | Что делает |
|-----------|-----|-----------|
| `TEXT_RULES` | В начале каждого теста | По ключевым словам в имени модели подбирает текст для запроса |
| `DEFAULT_HOST` / `DEFAULT_PORT` | В начале каждого теста | Куда стучаться (меняешь под свой проект) |
| `asserts.json` | Отдельный файл | Опциональные проверки — какой ответ ожидается от каждой модели |
## Шаг 1: Подготовка тестов к новому проекту
Скопируй `test_see_models.py` и/или `test_smc_models.py` в репозиторий нового проекта.
### 1.1 Укажи адрес сервера
В начале каждого тестового файла поменяй `DEFAULT_HOST` и `DEFAULT_PORT`:
```python
DEFAULT_HOST = "10.101.60.27" # IP вашего SEE/SMC
DEFAULT_PORT = 6184 # порт SEE: 6184, SMC: 6181
```
### 1.2 Настрой TEXT_RULES для своих моделей
`TEXT_RULES` — список `(keyword, text)`. **Первое совпадение побеждает**, поэтому специфичные правила должны идти раньше общих.
**Принцип**: для каждой модели нужен текст, который гарантированно вернёт непустой ответ.
Пример для SEE (`test_see_models.py`):
```python
TEXT_RULES = [
# специфичные — раньше
("fio", "Иванов Иван Иванович"), # модель ФИО → имя
("date", "на завтра"), # модель даты → фраза с датой
("phone", "8 913 456 78 90"), # модель телефона → номер
("number", "пятьсот двадцать три"), # модель числа → число прописью
("weekday", "в пятницу"), # модель дня недели → день
("mobilizac", "оператор"), # конкретная модель
("trud", "зарегистрироваться в цзн"), # конкретная модель
# общие — позже
("mfc", "записаться в мфц"), # fallback для всего MFC
("test", "test message"), # fallback для тестовых
]
```
**Как подобрать правила для нового проекта:**
1. Посмотри список моделей: `curl http://HOST:PORT/SEE_OR_SMC/models`
2. Для каждой модели подбери текст, который точно вернёт ответ
3. Сгруппируй по ключевым словам (одно правило может покрыть несколько моделей)
4. Расположи специфичные правила **выше**, общие — **ниже**
Пример для SMC (`test_smc_models.py`):
```python
TEXT_RULES = [
("филиал", "родники"), # филиалы → название филиала
("offices", "родники"),
("мфц", "записаться в мфц"), # модели МФЦ
("mfc", "записаться в мфц"),
("ekc", "записаться в екц"), # модели ЕКЦ
("екц", "записаться в екц"),
("minsoc", "какие выплаты"), # минсоц
("техническая", "подключите оператора"), # техподдержка
("тест", "тестовый запрос"),
]
```
## Шаг 2: Первый запуск без asserts
Запусти тест с `-v` (verbose), чтобы увидеть каждую модель и её ответ:
```bash
python3 test_see_models.py --host 10.101.60.25 --port 6184 -v
```
Вывод будет примерно таким:
```
── PRETRAINED ──────────────────────────────────────────────
✓ date → 2026-06-24
✓ number → 523
✓ fio → Ф:"Иванов" И:"Иван" О:"Иванович"
─── 6 passed, 0 empty
── CUSTOM ──────────────────────────────────────────────
✓ zags → отдел_центрального_оовосибирска
✓ weekday → пятница
✗ fio2 → empty
✗ Начало диалога → empty
─── 200 passed, 9 empty
```
Из вывода ты видишь:
- Какие модели работают (`✓ модель → результат`)
- Какие всегда пустые (`✗ модель → empty`)
- Какие есть хеш-варианты и бэкапы (у них тот же префикс, но с `~hash` или `-backup`)
## Шаг 3: Создание asserts
### 3.1 Правило `min_found`
| Тип модели | `min_found` | Почему |
|------------|-------------|--------|
| Базовая (без суффикса) | `1` | Должна всегда отвечать |
| Хеш-вариант (`~4f2d37c9...`) | `0` | Копия базы для тестирования, может не работать |
| `-backup` | `0` | Бэкап, может не работать |
| `-planned` | `0` | Запланированная, ещё не готова |
| `-new` | `0` | Экспериментальная, может не работать |
### 3.2 Формат для SEE (entity-модели)
SEE возвращает сущности с полями `text`, `calculated`, `confidence`:
```json
{
"asserts": [
{
"model": "fio",
"text": "Иванов Иван Иванович",
"checks": {
"min_found": 1,
"text_contains": "иван",
"calculated_contains": "Ф:",
"confidence_min": 0.3
}
}
]
}
```
| Поле checks | Что проверяет | Пример |
|-------------|--------------|--------|
| `min_found` | Минимум сущностей в ответе | `1` |
| `text_contains` | Подстрока в `text` первой сущности | `"иван"` |
| `calculated_contains` | Подстрока в `calculated` первой сущности | `"Ф:"` |
| `confidence_min` | Минимальный confidence первой сущности | `0.3` |
**Где брать значения**: из вывода `-v`. Например:
```
✓ fio → Ф:"Иванов" И:"Иван" О:"Иванович"
↑ берём отсюда подстроки для text_contains и calculated_contains
```
### 3.3 Формат для SMC (classifier-модели)
SMC возвращает классы с полями `class` и `confidence`:
```json
{
"asserts": [
{
"model": "МФЦ НСК",
"text": "записаться в мфц",
"checks": {
"min_found": 1,
"text_contains": "Запись",
"confidence_min": 0.5
}
}
]
}
```
| Поле checks | Что проверяет | Пример |
|-------------|--------------|--------|
| `min_found` | Минимум классов в ответе | `1` |
| `text_contains` | Подстрока в `class` первого класса | `"Запись"` |
| `confidence_min` | Минимальный confidence первого класса | `0.5` |
**Где брать значения**: из вывода `-v`:
```
✓ МФЦ НСК → Предварительная запись (1.000)
└── text_contains: "Запись"
└── confidence_min: 0.5
```
### 3.4 Полный assert для каждой строки `-v`
Проходишь вывод `-v` и для каждой строки создаёшь запись:
| Вывод `-v` | Запись в asserts |
|-------------|-----------------|
| `✓ fio → Ф:"Иванов" И:"Иван" О:"Иванович"` | `{"model": "fio", "text": "Иванов Иван Иванович", "checks": {"min_found": 1, "calculated_contains": "Ф:", "confidence_min": 0.3}}` |
| `✓ weekday → пятница` | `{"model": "weekday", "checks": {"min_found": 1, "text_contains": "пятница"}}` |
| `✓ zags~ffb403 → ...` (хеш) | `{"model": "zags~ffb403", "checks": {"min_found": 0}}` |
| `✗ fio2 → empty` | `{"model": "fio2", "checks": {"min_found": 0}}` |
### 3.5 Поле `text` в assert
Поле `text` в assert — опционально. Если оно есть, оно **переопределяет** `pick_text()`.
**Когда указывать `text`:**
- Модель работает с конкретным текстом, отличным от того что подбирает `pick_text`
- Например: модель `service_mfc` возвращает услуги, но `pick_text` даёт "записаться в мфц" — лучше явно указать "хочу получить водительское удостоверение"
**Когда НЕ указывать `text`:**
- `pick_text()` уже подбирает правильный текст
- Для хеш-вариантов и бэкапов — используй тот же текст что у базовой модели (укажи явно, чтобы не зависеть от порядка `pick_text`)
**Важно**: если указываешь `text` для хеш-варианта или бэкапа, используй тот же текст, что для базовой модели. Разные тексты могут не работать для копий.
Пример:
```json
// Базовая модель
{"model": "zags", "text": "загс центрального района", "checks": {"min_found": 1}}
// Хеш-вариант — тот же текст!
{"model": "zags~ffb403fff9f5802d53aac8a5c844af26", "text": "загс центрального района", "checks": {"min_found": 0}}
```
## Шаг 4: Запуск с asserts
```bash
python3 test_see_models.py --host 10.101.60.25 --port 6184 --asserts see_asserts.json -v
```
Теперь для каждой модели:
- `✓` — ответ непустой, проверки asserts пройдены
- `✗ → empty` — ответ пустой (но `min_found: 0`, тест проходит)
- `✗ → assert fail` — ответ есть, но не прошёл проверки (тест падает)
## Шаг 5: Исправление проблем
### Модель возвращает пустой ответ, а должна работать
1. Проверь текст в assert — попробуй другой текст напрямую через curl:
```bash
curl "http://HOST:PORT/see/entities/MODEL?text=ТЕКСТ&similarity=70"
```
2. Если другой текст работает — обнови `text` в assert
3. Если никакой текст не работает — модель действительно пустая, оставь `min_found: 0`
### Модель проходит без asserts, но падает с asserts
Проверь значения в `checks`:
- `text_contains` — проверь, что подстрока действительно есть в ответе
- `calculated_contains` — только для SEE entity-моделей
- `confidence_min` — возможно завышен, поставь 0.1 для ненадёжных моделей
### Хеш-вариант работает без asserts, но с asserts — пустой
Это значит assert для хеш-варианта переопределяет `text` на неправильный. Убедись, что `text` совпадает с базовой моделью.
## Полный пример: с нуля до готового набора
Допустим, у тебя новый проект с SEE на `10.10.10.10:6184`.
```bash
# 1. Первый запуск — смотрим что есть
python3 test_see_models.py --host 10.10.10.10 --port 6184 -v
# 2. Вывод показывает 50 моделей. Создаём see_asserts.json:
# - Для каждой базовой модели → min_found: 1 + проверки из ответа
# - Для хеш-вариантов и бэкапов → min_found: 0
# - Для пустых → min_found: 0
# 3. Запускаем с asserts
python3 test_see_models.py --host 10.10.10.10 --port 6184 --asserts see_asserts.json
# 4. Если есть ✗ assert fail — правим checks в asserts
# 5. Повторяем 3-4 пока все не пройдут
```
## Структура репозитория после настройки
```
мой-проект/
├── test_see_models.py # тест SEE (скопирован, изменён DEFAULT_HOST/PORT и TEXT_RULES)
├── test_smc_models.py # тест SMC (опционально)
├── see_asserts.json # проверки для SEE
├── smc_asserts.json # проверки для SMC (опционально)
└── README.md # краткое описание
```
## Важные замечания
1. **Порядок правил в TEXT_RULES важен** — специфичные ключевые слова (`"fio"`, `"phone"`) должны быть выше общих (`"mfc"`, `"test"`).
2. **Не указывай `text` в assert без необходимости** — если `pick_text()` уже подбирает правильный текст, не переопределяй. Каждый лишний `text` в assert — потенциальный источник расхождений.
3. **Хеш-варианты и бэкапы** — всегда `min_found: 0`. Они могут не работать, и это нормально.
4. **confidence_min для ненадёжных моделей** — ставь `0.1`, не `0.5`. Даже минимальный confidence лучше чем пустой ответ.
5. **`_find_assert` ищет сначала точное совпадение** — модель `ekc_smc-backup` не перепутается с `ekc_smc`. Порядок записей в asserts не критичен.
6. **Проверяй на всех серверах** — если у тебя несколько инсталляций (dev/stage/prod), гоняй тесты на каждой:
```bash
for host in 10.101.60.25 10.101.60.26 10.101.60.27; do
python3 test_see_models.py --host $host --port 6184 --asserts see_asserts.json
done
```

View File

@ -58,3 +58,7 @@ python3 test_smc_models.py --host 10.101.60.27 --port 6181
- `text_contains` — подстрока в тексте/классе первой сущности - `text_contains` — подстрока в тексте/классе первой сущности
- `calculated_contains` — подстрока в `calculated` (только entity) - `calculated_contains` — подстрока в `calculated` (только entity)
- `confidence_min` — минимальный confidence - `confidence_min` — минимальный confidence
## Как адаптировать под другой проект
См. [GUIDE.md](GUIDE.md) — полный гайд: от первого запуска до готового набора asserts.