AI-генерація unit-тестів: автоматичне покриття коду

Ручне покриття тестами відстає від темпу релізів, і рев'ю тоне в однотипних правках. Ми налаштовуємо AI-генерацію unit-тестів під ключ: від розбору кодової бази до вбудованого в конвеєр процесу. Покриття зростає в рази, а інженери повертаються до завдань, які справді потребують людини.
Часті запитання

AI-генерація unit-тестів: де ламається покриття

Рядкове покриття бреше: звіт показує 80%, а на релізі падають сценарії, яких у ньому не видно. Метрика рахує виконані рядки, а не пройдені гілки логіки — ранні виходи, тернарники, блоки обробки винятків залишаються без перевірок. Це і є вузьке місце покриття: цифра зростає, а впевненості перед викаткою — немає.

Окрема зона просідання — правки в старому коді. Зміна додає одну умову, загальний відсоток не рухається, а нова гілка не перевірена нічим.

Поріг на новий код у SonarQube рахує покриття за зміненими рядками — там одразу видно, що автоматичне покриття коду відстає від темпу правок, а регресії під час релізу приходять з дельти, а не з легасі.

Третя зона — обробка помилок: таймаути, повтори, часткові відмови зовнішніх сервісів, порожні та невалідні відповіді. Відтворювати їх руками довго й незручно, тому їх найчастіше й оминають — а спрацьовують у проді саме вони.

Четверта — інтеграційні стики: серіалізація, контракти між сервісами, мапінг між шарами та сховищем. Тести всередині модуля зелені, а на стику розходиться формат поля або губиться порожнє значення. Нижче розбираємо, як AI-генерація unit-тестів закриває ці чотири місця по кроках.

Що змінюється після впровадження: покриття, рев'ю, відмови

Перший ефект видно на шлюзі якості для нового коду.

Згенеровані тести з'являються в тій самій зміні, що й логіка, тому покриття не «підтягують» окремою задачею через місяць: частка перевірених рядків у самій зміні зростає з третини до 70–80% замість розмитого середнього по репозиторію.

Метрику видно в SonarQube поряд з іншими показниками збірки, тож зростання покриття коду — не звіт, а вимірювана умова проходження збірки.

Друге — час на рев'ю змін. Рев'юер перестає вручну проганяти очевидні сценарії: порожній вхід, межі діапазону, помилку зовнішнього виклику — вони вже зафіксовані тестом і падають самі.

Обговорення зміщується до контрактів та архітектури замість «чому на порожньому значенні все руйнується», і типова зміна вкладається в десятки хвилин замість годин.

Третє — клас відмов, який перестає доходити до стенда й продакшену. Регресії після точкових правок ловляться на етапі збірки: перевірка на межі модуля червоніє до викладки, а не в чергову зміну.

Частка відкатів у релізному циклі падає, і стабільність релізів перестає залежати від того, хто саме сьогодні на зв'язку.

Застереження, без якого ефект не тримається: тести мають бути супроводжуваними.

Ми генеруємо їх на кожну зміну, а не «на весь проєкт одразу», не дублюємо сценарії, що перетинаються, і не прив'язуємо перевірки до деталей реалізації — інакше за пару місяців їх видаляють, і покриття повертається на вихідний рівень.

Порівняння режимів: локальний запуск, конвеєр, виділений контур

Три режими запуску розрізняються не якістю генерації, а тим, де працює модель і куди йде вихідний код.

Локальний запуск тримає код на машині розробника, конвеєр збірки генерує тести на кожну зміну, а виділений контур розгортається всередині вашої мережі й обслуговує одразу кілька репозиторіїв.

Варіант Коли підходить Обмеження
Локальна генерація тестів Окремі модулі, ранні прототипи, код, який не можна виносити за периметр Швидкість упирається в ресурси робочої машини; немає єдиного набору правил — кожен пише тести по-своєму; результат погано відтворюється на іншому середовищі
Генерація в конвеєрі збірки Регулярна регресія, великі репозиторії, задача покрити вже написаний код Код іде до зовнішнього сервісу або потребує мережевого доступу; на великих репозиторіях прогін дроблять на частини, інакше зростає час збірки; потрібен розбір хибних спрацювань
Виділений контур Закритий код, вимоги щодо захисту даних, кілька команд і репозиторіїв Потребує розгортання й обслуговування всередині вашої інфраструктури; довше виводиться в роботу; потрібен регламент доступу та порядок оновлення моделей

Режими не виключають один одного: робочий сценарій — локальна генерація на гілці розробника, прогін у конвеєрі збірки для регресії та виділений контур для модулів з обмеженим доступом. Обмеження знімаються не вибором одного варіанта, а розмежуванням задач між ними.

Етапи впровадження: від аудиту кодової бази до передачі

Впровадження генерації тестів починається не з інструмента, а з розмітки кодової бази: де автоматичні перевірки дадуть сенс, а де впруться в приховані залежності та побічні ефекти. Порядок робіт однаковий і для моноліту, і для набору сервісів — змінюється лише обсяг аудиту.

  1. Аудит кодової бази. Розмічаємо модулі за зв'язністю, часткою розгалужень і наявністю явних контрактів. Окремо позначаємо код із зовнішніми викликами та глобальним станом — там генерація потребує ручного налаштування заглушок.

  2. Схема покриття. Розставляємо пріоритети: критичні шляхи, обробники помилок, граничні значення. Для кожного блоку фіксуємо цільовий показник покриття, щоб результат вимірювався, а не обговорювався на смак.

  3. Налаштування правил генерації. Задаємо шаблони, стиль іменування, структуру файлів і використовуваний фреймворк тестування. Прописуємо, які залежності підмінюються, а які перевіряються на реальних даних, і що не покривається автоматично принципово.

  4. Перевірка на вибірці модулів. Проганяємо генерацію на 10–20 репрезентативних модулях і порівнюємо з тестами, написаними вручну. Дивимося частку тих, що проходять з першого запуску, і час, який рев'юер витрачає на один згенерований тест.

  5. Вбудовування в контур розробки. Генерація запускається на змінених файлах, тести проходять те саме рев'ю, що й ручні, а падіння перевірок блокує злиття гілки.

  6. Передача документації та навчання. Віддаємо опис правил, конфігурації та розбір спірних випадків. Проводимо розбори на реальних модулях, щоб інженери могли змінювати правила генерації самі, без нашої підтримки.

Критерій завершення етапу — команда додає новий модуль у схему покриття й отримує осмислені тести без участі підрядника.

Що залишається в команди: конфігурації, схеми, регламенти

Генерація unit-тестів живе в репозиторії, а не в нашому акаунті.

Після здачі в команди залишаються налаштування, карта покриття, правила відбору модулів, документація та регламент супроводу — без цього набору рішення тримається до першої великої правки архітектури, далі тести застарівають, винятки накопичуються, прогін перестають читати.

  • Конфігурації генератора тестів — пороги покриття по модулях, правила винятків (згенерований код, міграції, обгортки зовнішніх сервісів), режими прогону. Поріг для окремого модуля змінюється без нашої участі.
  • Карта покриття модулів — по кожному модулю: які гілки закриті, де перевірено лише успішний сценарій, де розрив. Перебудовується на кожному прогоні, а не руками раз на квартал.
  • Правила відбору модулів — критерії потрапляння в генерацію: складність розгалуження, частота правок, місце в ланцюжку викликів. Пріоритети переглядаються в міру зростання коду.
  • Регламент оновлення тестів — що робити, коли згенерований тест упав: оновити очікування, зафіксувати дефект або занести у винятки. З відповідальним і порядком дій.
  • Документація щодо тестів — запуск локально й у збірці, склад наборів, читання звіту про покриття. Новий інженер входить у контур без листування з нами.
  • Передача рішення — доступи до репозиторію тестів і налаштувань прогону, розбір на живому модулі, перелік перевірок перед першою самостійною зміною. Прогін і правку команда виконує за нашої присутності.

Кейс: успадкований сервіс — покриття зросло втричі

Успадкований сервіс розрахунків жив у бойовій експлуатації близько дев'яти років: тести писалися точково, частина з них розійшлася з кодом і була вимкнена. Будь-яка правка в старому модулі означала ручний прогін сценаріїв на стенді, а регрес випливав уже після викатки.

Точка відліку

Покриття гілок трималося на 18%, до того ж JaCoCo рахував його лише за модулями, де тести взагалі збереглися — решта залишалася непрозорою.

На стенді стабільно фіксували 18–22 відмови на тиждень, а відновлення після правки в старому модулі займало 4–5 годин, з яких більше половини йшло на локалізацію причини.

Що змінили і що отримали

Спочатку статичний аналіз ранжував модулі за частотою правок і зв'язністю — генерація пішла туди, де ціна регресу максимальна.

Модель запропонувала тести за сигнатурами, типами повернення та розгалуженнями, мутаційна перевірка відсіяла набори, що проходять на будь-якій реалізації, а інженер затвердив лише ті, що перевіряють контракт модуля, а не його поточну поведінку.

Зовнішні виклики замінили записаними відповідями, тому набір став детермінованим і перестав залежати від стенда. Покриття гілок зросло до 56%, кількість відмов на стенді впала до 5–7 на тиждень, а час відновлення після правок у старому модулі скоротився до 40–50 хвилин.

Що робити, якщо кодова база вже покрита застарілими тестами?

Успадковане покриття майже завжди формальне: або прогін червоний і його навчилися ігнорувати, або зелений, але перевіряє не поведінку, а деталі реалізації. Довіра до прогонів падає до нуля — регресії випливають у проді, а зміни котяться «на око». Розбираємо, у якому порядку перебирати такий набір.

Спочатку інвентаризація та три кошики: тести, що падають під час навмисного поламання логіки; тести, прив'язані до реалізації — приватні методи, порядок викликів, точні знімки; і нестабільні, що залежать від середовища або порядку запуску. Орієнтир — не відсоток покриття, а частка тестів, що реагують на внесену помилку.

Далі відділяємо цінність від обв'язки. Сценарії, тестові дані та граничні значення, зібрані з минулих дефектів, переносимо — це найдорожчий актив набору. Переписуємо обв'язку: запуск, ізоляцію даних, підготовку оточення — саме через неї старий набір червоніє на незміненому коді.

Порядок перезбирання: спочатку стабілізуємо прогін — нестабільні тести йдуть у карантин з власником і терміном, але не видаляються мовчки. Потім закриваємо критичні шляхи: права доступу, розрахунки, міграції даних. І лише потім розширюємо покриття, генеруючи тести від актуальної поведінки коду.

Довіра до прогонів тримається на правилі: червоний результат блокує злиття, зелений означає «поведінка не змінилася». Тому тести детерміновані — ізольовані дані, фіксований час, жодних мережевих звернень. Тоді набір зростає за рахунок видалення дублів, а не часу прогону.

Часті сумніви: якість, хибні спрацювання, супровід

Сумніви перед впровадженням зазвичай зводяться до чотирьох питань: чи формальні згенеровані перевірки, чи не почне збірка падати на рівному місці, чи не витече вихідний код і хто відповідає за набір після відходу автора. Кожне з них перевіряється вимірювано, а не запевненнями.

Головною метрикою вважаємо не частку покритих рядків — її легко набрати перевірками, які нічого не перевіряють, — а мутаційну стійкість і частку нестабільних прогонів.

Як переконатися, що перевірки надійні, а не просто «зелені»?

Запускаємо мутаційне тестування: у код вносяться типові дефекти — інверсія умови, зсув межі, підміна значення, що повертається, — і рахується частка виявлених. Гілки з нульовою чутливістю йдуть на доопрацювання сценаріїв, а набір, який проходить через раз, у постачання не йде.

Звідки беруться хибні спрацювання і як ви їх прибираєте?

Джерело більшості хибних падінь — недетермінізм: час, випадкові значення, порядок обходу колекцій, зовнішні сервіси. Генератори фіксуються зерном, час і мережа підмінюються керованими двійниками, дані готуються в ізольованій базі й відкочуються після прогону. Перевірка відтворюється однаково в розробника та в складальному контурі.

Код іде на зовнішні сервери?

Розгортаємо всередині вашого контуру: модель працює на ваших потужностях, вихідники та історія змін не покидають периметр, вихідні звернення закриваються на рівні мережі.

Доступ — за вашими ролями, артефакти й журнали залишаються у вас, а каталоги, які не можна показувати навіть локальній моделі, виключаються політикою.

Що із супроводом, коли автори підуть з проєкту?

Набір перевірок застаріває під час рефакторингу й потребує власника. Передаємо регламент оновлення та видалення перевірок, склад метрик і точки контролю в складальному контурі — команда веде набір сама. За бажанням залишаємося на супроводі з фіксованим терміном реакції на падіння.

Обговоримо задачу: що потрібно від вас для старту

Щоб повернутися з оцінкою та планом робіт, а не із загальними словами, нам потрібен контекст про код і процес розробки. Нижче — вхідні дані для оцінки: чим більше пунктів закрито, тим точніші терміни й тим менше уточнень на старті проєкту.

  • Репозиторій або його частина, яку плануємо покривати: мова, фреймворк, структура модулів і точок входу.
  • Що вже є: наявні тести, чим запускаються, поточне покриття — які гілки логіки перевірені, а які ні.
  • Як збирається проєкт: команда збірки, час повного прогону тестів, чим рахуємо покриття.
  • Обмеження щодо доступів: чи можна вивантажувати фрагменти коду в зовнішні сервіси або генерація йде лише всередині вашого контуру.
  • Вимоги до перевірок: які сценарії обов'язкові, де замість реальних залежностей допустимі підставні об'єкти.
  • Критерій приймання: яка частка покриття і які модулі вважаються закритими, хто це підтверджує.
  • Порядок роботи з кодом: куди вносимо зміни, хто рев'юїть, чи потрібна автоматична перевірка на кожному злитті.

Цього достатньо, щоб ми повернулися з оцінкою та планом робіт: обсяг, етапи, зона відповідальності на вашому боці та порядок запуску генерації тестів. Опишіть задачу у вільній формі — обговоримо деталі й запропонуємо формат старту.

Напрямки AI-розробки

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1141