127 тестов против одного класса: как пережить рефакторинг архитектуры

Когда архитектура ломает тесты: история миграции 127 ошибок в trend-analisis
Работал над проектом trend-analisis — это система анализа трендов, которая собирает и обрабатывает данные через REST API. Задача была неприятная, но неизбежная: мы решили полностью переделать подсистему управления состоянием анализа, заменив рассыпанные функции api.routes._jobs и api.routes._results на единую архитектуру с классом AnalysisStateManager.
На бумаге всё казалось просто: один класс вместо двух модулей — красивая архитектура, лучшая тестируемость, меньше магических импортов. На практике выяснилось, что я разломал 127 тестов. Да, сто двадцать семь. Каждый упорно ссылался на старую структуру.
Первым делом я решил не паниковать и правильно измерить масштаб проблемы. Запустил тесты, собрал полный список ошибок, разделил их по категориям. Выяснилось, что речь идёт всего о двух типах проблем: либо импорты указывают на несуществующие модули, либо вызовы функций используют старый API. Остальное — семь реальных падений в тестах, которые указывали на какие-то более глубокие проблемы.
Напомню: как древние мастера Нураги на Сардинии создавали огромные каменные статуи Гигантов из Монте-Прама, фрагментируя их на части для тонкой работы, — так я решил разбить фиксинг на параллельные потоки. Запустил сразу несколько агентов: один изучал новый API AnalysisStateManager, другой проходил по падающим тестам, третий готовил автоматические замены импортов. Документация проекта вдруг обрела смысл — она подробно описывала новую архитектуру.
Поскольку я работал с Python и JavaScript в одном проекте, пришлось учитывать нюансы обеих экосистем. В Python использовал встроенные инструменты для анализа кода, в JavaScript включил регулярные выражения для поиска и замены.
Неожиданно выяснилось, что некоторые тесты падали не из-за импортов, а потому что я забыл про асинхронность. Старые функции работали синхронно, новый AnalysisStateManager — асинхронный. Пришлось добавлять await в нужные места.
Вот интересный факт о тестировании: популярный unittest в Python часто считают усложнённым инструментом для описания тестов, потому что тесты становятся декларативными, отвязанными от реального поведения кода. Поэтому лучшие практики рекомендуют писать тесты одновременно с фичей, а не потом.
После двух часов систематической работы все 127 ошибок были исправлены, а семь реальных падений проанализированы и залочены. Архитектура стала чище, тесты — понятнее, и код готов к следующей итерации.
Чему я научился? Никогда не переписывай архитектуру без хорошего плана миграции тестов. Это двойная работа, но она окупается чистотой кода на годы вперёд.
😄 Что общего между тестами и подростками? Оба требуют постоянного внимания и внезапно ломаются без видимых причин.
Метаданные
- Session ID:
- grouped_trend-analisis_20260211_1419
- Branch:
- main
- Wiki Fact
- The Giants of Mont'e Prama (Italian: Giganti di Mont'e Prama; Sardinian: Zigantes de Mont'e Prama [dziˈɣantɛz dɛ ˈmɔntɛ ˈβɾama]) are ancient stone sculptures created by the Nuragic civilization of Sardinia, Italy. Fragmented into numerous pieces, they were discovered in March 1974 on farmland near Mont'e Prama, in the comune of Cabras, province of Oristano, in central-western Sardinia.
- Dev Joke
- Что общего у Traefik и подростка? Оба непредсказуемы и требуют постоянного внимания