18 KiB
Как создать автотесты для другого проекта
Этот гайд описывает полный цикл создания автотестов для 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:
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):
TEXT_RULES = [
# специфичные — раньше
("fio", "Иванов Иван Иванович"), # модель ФИО → имя
("date", "на завтра"), # модель даты → фраза с датой
("phone", "8 913 456 78 90"), # модель телефона → номер
("number", "пятьсот двадцать три"), # модель числа → число прописью
("weekday", "в пятницу"), # модель дня недели → день
("mobilizac", "оператор"), # конкретная модель
("trud", "зарегистрироваться в цзн"), # конкретная модель
# общие — позже
("mfc", "записаться в мфц"), # fallback для всего MFC
("test", "test message"), # fallback для тестовых
]
Как подобрать правила для нового проекта:
- Посмотри список моделей:
curl http://HOST:PORT/SEE_OR_SMC/models - Для каждой модели подбери текст, который точно вернёт ответ
- Сгруппируй по ключевым словам (одно правило может покрыть несколько моделей)
- Расположи специфичные правила выше, общие — ниже
Пример для SMC (test_smc_models.py):
TEXT_RULES = [
("филиал", "родники"), # филиалы → название филиала
("offices", "родники"),
("мфц", "записаться в мфц"), # модели МФЦ
("mfc", "записаться в мфц"),
("ekc", "записаться в екц"), # модели ЕКЦ
("екц", "записаться в екц"),
("minsoc", "какие выплаты"), # минсоц
("техническая", "подключите оператора"), # техподдержка
("тест", "тестовый запрос"),
]
TEXT_RULES покрывает только типовые модели (fio, date, phone, mfc, zags...) — те, для которых по ключевому слову можно угадать подходящий текст. Одно правило покрывает десятки похожих моделей.
Для узкоспецифичных моделей проекта, где ключевое слово не даёт нужной точности, используй text в asserts (см. Шаг 3.6).
Шаг 2: Первый запуск без asserts
Запусти тест с -v (verbose), чтобы увидеть каждую модель и её ответ:
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) - Какие есть варианты с ID датасета и бэкапы (тот же префикс, но с
~IDили-backup)
Шаг 3: Создание asserts
3.1 Правило min_found
| Тип модели | min_found |
Почему |
|---|---|---|
| Базовая (без суффикса) | 1 |
Должна всегда отвечать |
ID датасета (~4f2d37c9...) |
0 |
Копия модели на другом датасете, может не работать |
-backup |
0 |
Бэкап, может не работать |
-planned |
0 |
Запланированная, ещё не готова |
-new |
0 |
Экспериментальная, может не работать |
3.2 Формат для SEE (entity-модели)
SEE возвращает сущности с полями text, calculated, confidence:
{
"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:
{
"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 → ... (ID датасета) |
{"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()уже подбирает правильный текст- Для вариантов с ID датасета и бэкапов — используй тот же текст что у базовой модели (укажи явно, чтобы не зависеть от порядка
pick_text)
Важно: если указываешь text для варианта с ID датасета или бэкапа, используй тот же текст, что для базовой модели. Разные тексты могут не работать для копий.
Пример:
// Базовая модель
{"model": "zags", "text": "загс центрального района", "checks": {"min_found": 1}}
// Хеш-вариант — тот же текст!
{"model": "zags~ffb403fff9f5802d53aac8a5c844af26", "text": "загс центрального района", "checks": {"min_found": 0}}
3.6 Когда TEXT_RULES не хватает
Философия тестов — два уровня проверки:
| Уровень | Инструмент | Вопрос |
|---|---|---|
| 1 — санитарный | TEXT_RULES | Модель живая? Отвечает хоть что-то? |
| 2 — проверочный | asserts | Модель отвечает правильно? |
TEXT_RULES даёт быстрый ответ «живая/мёртвая» для типовых моделей. Но есть модели, которым нужен специфичный текст, недоступный для угадывания по ключевому слову.
Пример: модель Конкретика по УК~ffb403... — TEXT_RULES по ключевому слову "конкретик" возвращает "конкретный вопрос". Текст слишком размытый, модель не находит сущностей и возвращает пустой ответ.
Решение: добавить text в assert с точной формулировкой:
{
"model": "Конкретика по УК~ffb403fff9f5802d53aac8a5c844af26",
"text": "Найти свою УК",
"checks": {"min_found": 0}
}
Это не баг, а дизайн:
- TEXT_RULES универсален и переносим между проектами (скопировал тесты — работает)
- asserts пишется под конкретный проект и покрывает специфичные модели
- Без asserts — быстрый санитарный прогон, с asserts — полная валидация
Шаг 4: Запуск с asserts
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: Исправление проблем
Модель возвращает пустой ответ, а должна работать
- Проверь текст в assert — попробуй другой текст напрямую через curl:
curl "http://HOST:PORT/see/entities/MODEL?text=ТЕКСТ&similarity=70" - Если другой текст работает — обнови
textв assert - Если никакой текст не работает — модель действительно пустая, оставь
min_found: 0
Модель проходит без asserts, но падает с asserts
Проверь значения в checks:
text_contains— проверь, что подстрока действительно есть в ответеcalculated_contains— только для SEE entity-моделейconfidence_min— возможно завышен, поставь 0.1 для ненадёжных моделей
Хеш-вариант работает без asserts, но с asserts — пустой
Это значит assert для варианта с ID датасета переопределяет text на неправильный. Убедись, что text совпадает с базовой моделью.
Полный пример: с нуля до готового набора
Допустим, у тебя новый проект с SEE на 10.10.10.10:6184.
# 1. Первый запуск — смотрим что есть
python3 test_see_models.py --host 10.10.10.10 --port 6184 -v
# 2. Вывод показывает 50 моделей. Создаём see_asserts.json:
# - Для каждой базовой модели → min_found: 1 + проверки из ответа
# - Для вариантов с ID датасета и бэкапов → 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 # краткое описание
Важные замечания
-
Порядок правил в TEXT_RULES важен — специфичные ключевые слова (
"fio","phone") должны быть выше общих ("mfc","test"). -
Не указывай
textв assert без необходимости — еслиpick_text()уже подбирает правильный текст, не переопределяй. Каждый лишнийtextв assert — потенциальный источник расхождений. -
Хеш-варианты и бэкапы — всегда
min_found: 0. Они могут не работать, и это нормально. -
confidence_min для ненадёжных моделей — ставь
0.1, не0.5. Даже минимальный confidence лучше чем пустой ответ. -
_find_assertищет сначала точное совпадение — модельekc_smc-backupне перепутается сekc_smc. Порядок записей в asserts не критичен. -
Проверяй на всех серверах — если у тебя несколько инсталляций (dev/stage/prod), гоняй тесты на каждой:
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