diff --git a/rules/patterns/testing-policy/contract.md b/rules/patterns/testing-policy/contract.md new file mode 100644 index 0000000..c84dd89 --- /dev/null +++ b/rules/patterns/testing-policy/contract.md @@ -0,0 +1,82 @@ +# Contract: Testing Policy + +Version: 1.0 + +## Purpose + +Определяет когда писать тесты, когда не писать, и как их поддерживать. +Применяется ко всем проектам на Go. Агенты следуют этим правилам самостоятельно, без запроса подтверждения. + +--- + +## Когда тест обязателен + +Тест пишется всегда, когда код делает нетривиальное преобразование данных или реализует бизнес-логику: + +- **Парсеры** — любой код, читающий внешний формат (XML, JSON, CSV, бинарный) +- **Трансформации** — конвертация единиц, нормализация, маппинг полей +- **Бизнес-правила** — расчёты, фильтрация, агрегация, приоритизация +- **Граничные случаи** — пустой ввод, нулевые значения, переполнение, отсутствующие поля +- **Регрессии** — если баг был найден, тест фиксирует его до исправления + +Тест пишется в том же коммите, что и функциональность. Функциональность без теста (там где он обязателен) — неполный коммит. + +--- + +## Когда тест не нужен + +Тест не пишется на код, где он не даёт ценности: + +- Геттеры и сеттеры: `func (s *Server) Port() int { return s.port }` +- Конфиг-структуры и константы +- Тривиальный клей: передача параметров, инициализация, dependency wiring +- Логирование и форматирование вывода +- HTTP-хендлеры без бизнес-логики (только роутинг и вызов сервиса) + +--- + +## Структура теста + +Использовать стандартный Go `testing`. Табличные тесты (`[]struct{ ... }`) — когда случаев больше двух. + +```go +func TestParseGPUSensor(t *testing.T) { + tests := []struct { + name string + xml string + want int + }{ + {"normal", `290`, 29}, + {"zero", `0`, 0}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := parseGPUTemp(tt.xml) + if got != tt.want { + t.Fatalf("got %d, want %d", got, tt.want) + } + }) + } +} +``` + +Фикстуры (XML, JSON, бинарные данные) — инлайн-константы или файлы в `testdata/`. +Не использовать реальные сетевые вызовы и реальную БД в юнит-тестах. + +--- + +## Мейнтейнс + +- Сломанный тест — чинится или удаляется в том же коммите где сломался. +- Закомментированный тест — не допускается. Если тест неактуален — удалить. +- Тест, проверяющий удалённую функциональность — удалить вместе с функциональностью. + +--- + +## Инструкция для агентов (Codex, Claude) + +1. При добавлении функциональности — проверь по списку выше, попадает ли код в категорию "обязателен". +2. Если да — напиши тест в том же коммите, без запроса подтверждения. +3. Если нет — не пиши тест, не упоминай его отсутствие. +4. При удалении функциональности — удали соответствующие тесты. +5. При обнаружении закомментированных или сломанных тестов — удали или почини.