Skip to content

Testing and the Gate ru

Se.Cherkasov edited this page Aug 23, 2026 · 1 revision

Тесты и гейт

English · Русский

Стек тестов

kotlin("test") на бэкенде JUnit 5. Ни Kotest, ни MockK, ни ktlint — фейки написаны руками, а роль линта играет Android lint внутри ./gradlew build. Покрытие — Kover (./gradlew koverHtmlReport).

./gradlew test allTests   # один `test` пропускает мультиплатформенные модули

Тесты живут в commonTest, если поведение не по-настоящему платформенное; UI-тесты используют оболочку-харнесс из Слоя UI и требуют дисплея (в CI — xvfb-run --auto-servernum).

Цикл TDD

  1. RED — сначала падающий тест, и убедиться, что он падает по задуманной причине, а не на ошибке компиляции.
  2. GREEN — минимальная реализация: контракты в commonMain, платформенные библиотеки за expect/actual, осиротевший код удалён тем же коммитом.
  3. Гейт — стадии, которые изменение реально должно.
  4. Ревью — фан-аут агентов.

Новый тест перепрогоняется с откаченным фиксом — доказать, что он действительно ловит регрессию.

Обвязка

tools/harness/ не доверяет циклу, а обеспечивает его:

tools/harness/gate.py status        # что это за изменение и что оно ещё должно
tools/harness/gate.py run           # прогнать ровно то, что должно, по порядку
tools/harness/gate.py red --tests '*Pattern*' --file path/to/Test.kt
tools/harness/gate.py task bug 133  # переопределить автоопределённый вид
tools/harness/gate.py reviewers     # какие ревьюверы нужны этому изменению

Что изменение должно, зависит от того, что оно такое:

Вид Как определяется Что должен
docs в диффе нет кода ничего
refactor ветка refactor/ chore/ perf/ checks · tests · build · detekt · ревьюверы
feature ветка feat/ или безымянная ветка с кодом то же плюс тронутый тест
bug ветка fix/ bug/ hotfix/ либо объявлено то же плюс тест, записанный падающим до фикса

Области добавляют стадии: UI или Android в диффе подтягивают :androidApp:compileDebugKotlin, серверная работа — java-ревьювера, терминальная — ревьювера производительности. Объявление может сделать гейт строже, но никогда — слабее.

Почему стадию красит только раннер

Раннер выполняет стадию, читает код возврата и пришпиливает результат к дайджесту дерева, на котором он выполнялся. Ручной прогон Gradle не записывается — не потому, что ручные прогоны запрещены, а потому, что ничто вне раннера не может доказать, какому коду принадлежал код возврата. Любая правка после этого переоткрывает гейт, потому что дайджест сдвинулся; коммит не переоткрывает, а откат изменения возвращает то зелёное состояние, которое было.

Стадии: checks (детерминированные правила проекта), tests, build (с линтом), detekt и android, когда дифф трогает UI. Логи — в .git/skerry-gate/<стадия>.log.

detekt валится только на новых находках; существующие лежат в gradle/detekt-baseline-*.xml, и перебазировать их, чтобы заглушить собственную находку, нельзя.

Осознанный обход — SKERRY_GATE_OVERRIDE=1, и он означает, что причина проговаривается вслух. От защиты main он не освобождает.

У самой обвязки есть тесты: python3 tools/harness/selftest.py (~70 случаев, две секунды, без Gradle). Меняешь правило — меняешь и их.

Детерминированные проверки

tools/harness/checks.py блокирует коммит на правилах, не требующих суждения: переводы полны в en + ru + zh, нет захардкоженного текста UI, Txt/Sym вместо сырых Text/Icon, дизайн-токены вместо hex, нет Kotest и MockK, зависимости через version catalog, atomicWriteUtf8 на путях с секретами, у нового хоткея есть строка в настройках.

Фан-аут ревью

Когда ветка зелёная, ревьюверы идут параллельно по git diff main...HEAD плюс рабочее дерево:

Ревьювер Что ищет
skerry-reviewer собственные правила проекта — паритет, примитивы, хранилище, каталог абстракций
skerry-kotlin-reviewer структурная конкурентность, рекомпозиция Compose, идиомы Kotlin для этого стека
skerry-security-reviewer хранилище и его криптография, недоверенный ввод протоколов, граница sync/команд
silent-failure-hunter проглоченные исключения, плохие фолбэки, ошибки, которые никуда не всплывают
pr-test-analyzer покрывают ли тесты поведение, а не строки

Первые три лежат в .claude/agents/, поэтому фан-аут приезжает вместе с клоном. Правила: ревьюверы только читают, никогда не переключают ветки, каждая находка либо чинится, либо явно отклоняется с причиной, фикс, меняющий поведение, возвращается к шагу 1, и два круга на ветку — третий запрашивает мейнтейнер. Находки складываются в .git/skerry-gate/reviews/.

CI

Workflow Триггер Что делает
ci.yml пуши и PR JDK 21, Android SDK, test allTests под xvfb-run, detekt, выгрузка отчётов
release.yml тег v* (или вручную) собирает .deb/.rpm/.AppImage (x64 + arm64), .msi, .dmg (arm64 + x64), подписанный .apk и SHA256SUMS.txt, публикует черновик релиза
server-image.yml тег server-v* собирает мультиархитектурный образ сервера, дымовым тестом проверяет, что контейнер стал healthy, пушит в Docker Hub
codeql.yml по расписанию и на PR сканирование кода

CI не заменяет локальный гейт: он гоняет те же тесты, но именно гейт связывает зелёный результат с тем самым деревом, которое коммитится.

Clone this wiki locally