ИИ в тестировании кода: как генерировать unit-тесты и находить ошибки

Kodik
Команда Kodik8 минут чтения

В статье разбираем, как можно использовать ИИ в тестировании кода: генерировать unit-тесты, искать edge cases, анализировать ошибки, готовить тестовые данные и проверять результат.

ИИ в тестировании кода: как генерировать unit-тесты и находить ошибки

После каждого изменения кода приходится проверять старые сценарии, новые условия и неожиданные входные данные. Искусственный интеллект помогает перенести часть этой рутины в автоматические проверки: составить unit-тесты, предложить неочевидные входные данные, разобраться с падением теста.

При этом использование ИИ в тестировании особенно полезно там, где поведение функции можно описать однозначно. В статье разберём практический процесс: от постановки задачи модели до ревью и запуска полученных проверок.

Что такое ИИ в тестировании кода

Это применение языковых моделей (LLM), AI-ассистентов и AI-IDE для анализа исходников, подготовки тестовых сценариев, генерации автотестов и разбора ошибок.

Обычный ИИ для программирования может написать функцию или объяснить её устройство. При тестировании задача другая: найти условия, в которых функция поведёт себя неправильно, и выразить ожидаемый результат через проверяемые утверждения — assertions.

Обычно нейросети в тестировании работают с текстовым представлением кода и требований. Они способны заметить пропущенную ветку if или предложить проверку на пустую коллекцию, но не знают требований к продукту, если вы их не сообщили.

В отличие от обычного запуска тестового фреймворка, AI в тестировании помогает придумать сами сценарии и подготовить код проверок. При этом модель не выполняет тесты просто потому, что написала их.

Где ИИ помогает при тестировании кода

Генерация unit-тестов

Unit-тест проверяет отдельную функцию, метод или небольшой модуль, по возможности изолированный от базы данных, сети и других внешних зависимостей. Поэтому его результат обычно проще воспроизвести и объяснить, чем результат сквозной проверки приложения.

Например, для функции расчёта скидки можно попросить позитивные сценарии (скидка применяется), негативные (неподходящий промокод отклоняется) и граничные (заказ на один рубль ниже порога). Такая генерация unit-тестов ускоряет создание первоначального набора проверок, но правильные значения в assert должны следовать из требований, а не только из текущей реализации.

Инструменты, работающие прямо с репозиторием, могут учитывать импорты, соглашения об именовании и существующие тесты. О различиях таких сред рассказываем в обзоре лучших AI-IDE.

Поиск edge cases и слабых мест в логике

Типовые проверки часто охватывают «счастливый путь»: корректные данные приводят к корректному результату. Ошибки же прячутся на границах. Попросите модель перечислить edge cases, не создавая тесты сразу. Так проще сначала оценить предложенные сценарии, а потом превратить нужные в код.

Особенно полезно проверить ноль, отрицательные числа, пустые строки и списки, None или null, неверные типы, дубли, большие значения, несовпадающие часовые пояса, а также сочетания нескольких условий.

Пример: функция разрешает бесплатную доставку от 3000 рублей включительно. Тесты на 2500 и 4000 рублей не обнаружат ошибку в условии > 3000. Проверка ровно на 3000 — обнаружит.

Анализ ошибок и падающих тестов

Когда тест не проходит, ИИ можно передать само утверждение, фрагмент реализации, сообщение об ошибке и stack trace. Модель сопоставит ожидаемый и фактический результат, предложит гипотезы: ошибка в условии, неправильный mock, неверно подготовленные тестовые данные или некорректное ожидание.

Хороший результат анализа — проверяемые гипотезы, а не категоричный диагноз. Исправление нужно запускать и проверять отдельно: объяснение LLM само по себе ничего не доказывает.

Подготовка mocks, fixtures и тестовых данных

Если функция обращается к внешнему API, в unit-тесте этот вызов часто подменяют mock-объектом. Он возвращает заранее заданные данные и позволяет проверить, с какими аргументами вызвали зависимость. Fixture создаёт повторяемое окружение: например, тестового пользователя, настройки или временный файл.

ИИ умеет заготовить mocks и fixtures под pytest, Jest или JUnit, предложить наборы входных и выходных данных. Если важен реальный контракт между сервисами, потребуются и интеграционные проверки: mock не покажет, что внешняя система действительно отвечает ожидаемым образом.

ИИ в автоматизации тестирования

Этот подход полезен не только при создании нового файла с тестами. Он помогает расширить регрессионный набор после исправления бага, привести однотипные проверки к параметризованному виду и подготовить тесты для запуска в CI/CD.

Иногда применяют и агенты ИИ в тестировании: агент может изучить несколько файлов, создать тесты, запустить команду, прочитать ошибку и предложить исправление.

Как генерировать unit-тесты с помощью ИИ

Чтобы получить пригодные проверки, недостаточно написать «покрой функцию тестами». Нужен небольшой контракт: что функция принимает, что должна возвращать и какие ошибки считать ожидаемыми. Здесь работает та же логика, что и в промпт-инжиниринге: конкретика полезнее длинного, но расплывчатого запроса.

  1. Выберите единицу проверки. Начните с функции с понятными входами и выходами. Для большого класса выделите метод и его зависимости.
  2. Укажите стек. Язык, версию, тестовый фреймворк (pytest, Jest, JUnit), способ импорта и правила проекта.
  3. Опишите ожидаемое поведение. Зафиксируйте бизнес-правила, допустимые значения, исключения, условия на границах и принцип округления, если он важен.
  4. Попросите сначала матрицу сценариев. Пусть ИИ перечислит вход, ожидаемый выход и причину проверки. Удалите лишнее и дополните пропущенные ветки.
  5. Получите тестовый код. Попросите параметризацию повторяющихся случаев и минимальные заглушки там, где без них не обойтись.
  6. Запустите тесты в окружении проекта. Разберите падения, исправьте неверные ожидания или обнаруженный дефект, затем повторите запуск.

Для больших кодовых баз важен не только промпт, но и контекст проекта: доступ к сигнатурам, зависимостям и соседним тестам помогает не выдумывать структуру репозитория. При этом возможность подключить контекст не гарантирует, что модель правильно его истолкует.

Генерация unit-тестов: практический пример на Python

Представим функцию расчёта доставки. По требованиям обычная доставка стоит 300 рублей при сумме заказа меньше 3000 рублей и бесплатна начиная с 3000. Экспресс-доставка всегда стоит 600 рублей. Отрицательная сумма запрещена.

В коде разработчик ошибся в одном символе:

# delivery.py
def shipping_fee(total: int, express: bool = False) -> int:
    if total < 0:
        raise ValueError("negative total")
    if express:
        return 600
    return 0 if total > 3000 else 300  # Ошибка: нужно >=

Проверка, построенная по текущему коду, может повторить это неверное условие. А тест, построенный по требованиям, зафиксирует дефект:

# test_delivery.py
import pytest
from delivery import shipping_fee

@pytest.mark.parametrize("total,express,expected", [
    (0, False, 300),
    (2999, False, 300),
    (3000, False, 0),
    (3001, False, 0),
    (3000, True, 600),
])
def test_shipping_fee(total, express, expected):
    assert shipping_fee(total, express) == expected

def test_negative_total():
    with pytest.raises(ValueError):
        shipping_fee(-1)

Запуск python -m pytest -q покажет падение на значении 3000: функция вернёт 300 вместо ожидаемого 0. После замены > на >= все приведённые случаи должны пройти. Использованный декоратор @pytest.mark.parametrize поддерживается официальной документацией pytest.

Смысл примера не в количестве тестов, а в независимом источнике ожиданий. Если бы модель выводила правила только из исходного кода, она могла бы уверенно подтвердить уже существующий баг. Правила продукта должны оставаться главным ориентиром.

Примеры запросов к ИИ для тестирования кода

Запрос на написание unit-тестов

Слабый: «Напиши тесты для этого метода».

Сильный:

Проект на Python 3.12, тесты пишем на pytest. Ниже функция shipping_fee и правила расчёта доставки. Сначала составь таблицу позитивных, негативных и граничных сценариев. Затем создай test_delivery.py, используя параметризацию. Не меняй исходную функцию. Для каждого теста укажи, какое требование он проверяет. Если поведение не определено, задай вопрос, а не придумывай правило.

Если работа ведётся в Kodik, такой запрос можно дополнить просьбой изучить соседние тесты и принятые в проекте соглашения. Доступ к файлам помогает согласовать стиль тестов, но ожидаемую бизнес-логику всё равно нужно описать явно.

Запрос на поиск пограничных случаев

Слабый: «Найди баги в функции».

Сильный:

Проанализируй метод оформления заказа на TypeScript. Его контракт и код приведены ниже. Найди возможные edge cases: пустая корзина, повторный промокод, отрицательное количество, ошибка платёжного API, дублирующий запрос. Верни таблицу: условие, риск, ожидаемое поведение по требованиям, предлагаемый тест. Если в требованиях пробел, пометь его как вопрос. Пока не переписывай код.

Этот приём особенно полезен перед рефакторингом: разработчик заранее видит, какие ветки ещё не зафиксированы тестами. Но не стоит автоматически превращать все предположения модели в требования к продукту.

Запрос на анализ падающего теста

Слабый: «Исправь тест, он падает».

Сильный:

Вот реализация, тест, полный stack trace и версии библиотек. Ожидаемое поведение описано отдельно. Назови до трёх наиболее вероятных причин падения и предложи минимальный способ проверить каждую. Разделяй ошибку в продукте, ошибку в тесте и проблему окружения. Не меняй assertion только ради зелёного статуса; если предлагаешь патч, объясни, почему он соответствует контракту.

Такая постановка не даёт модели пойти по самому простому пути — подогнать тест под фактический результат.

Где ИИ может ошибаться при генерации тестов

  • Подмена требований реализацией. Модель изучает функцию и воспринимает её текущее поведение как правильное. Тест закрепляет баг вместо того, чтобы его обнаружить.
  • Вымышленные API. В тестах появляются несуществующие методы, неподдерживаемые аргументы или импорты из другой версии библиотеки. Такие проверки не запускаются.
  • Ложное чувство покрытия. Процент строк в отчёте может быть высоким, хотя критические условия и исключения не проверены. Метрика покрытия показывает, что выполнялось, но не доказывает качество утверждений.
  • Хрупкие mocks. Избыточные заглушки делают тест зависимым от внутреннего устройства функции. После безобидного рефакторинга он ломается, хотя поведение не изменилось.
  • Неправильные тестовые данные. Модель предлагает значения, невозможные в доменной модели, либо пропускает ограничения, заданные схемой базы данных.

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

Не стоит отдавать агенту безусловное право «чинить всё до зелёного статуса». ИИ-агенты в разработке могут выполнять цепочки действий, но при неверно заданной цели способны удалить важную проверку или изменить ожидание вместо исправления дефекта. Просматривайте diff и запускайте регрессионные тесты перед слиянием изменений.

Безопасность при работе с кодом и тестами

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

Не передавайте без необходимости пароли, токены, API-ключи, приватные конфигурации, персональные данные и содержимое закрытых репозиториев. Секреты могут попасть не только в промпт, но и в stack trace, лог ошибки или fixture. Для снижения риска используют маскирование чувствительных данных, в том числе KodikShield, и ограничивают доступ агента только нужными ресурсами.

Тестируйте код с ИИ в контексте проекта. Kodik помогает анализировать исходники, готовить unit-тесты, искать граничные случаи и разбирать ошибки прямо в процессе разработки. При этом результаты остаются предметом обычного ревью и запуска тестов. Скачать Kodik.

Если выбираете AI-инструмент для автоматизации тестирования...

...присмотритесь к Kodik.

Начните работу с ИИ без опасений об утечке данных

Вопросы и ответы

Что такое ИИ в тестировании кода?

Это применение языковых моделей и инструментов разработки для анализа функций, генерации проверок, поиска проблемных сценариев и объяснения сбоев.

Может ли ИИ сам писать unit-тесты?

Да. По коду и описанию поведения модель может подготовить тесты на pytest, Jest, JUnit и других фреймворках.

Какие данные нужно дать ИИ для генерации тестов?

Нужны код или интерфейс функции, стек и версии библиотек, бизнес-правила, входные и выходные данные, ограничения и используемый фреймворк. Чем точнее контракт, тем меньше риск случайно закрепить баг.

Почему сгенерированные тесты нужно проверять?

Они могут использовать неверные ожидания, неподходящие заглушки и несуществующие API. Даже прошедший тест бесполезен, если не проверяет требование, ради которого был написан.

Может ли ИИ найти ошибки в коде?

Он может заметить подозрительные условия и подсказать проверки, которые воспроизводят дефект. Подтверждают ошибку воспроизводимый сценарий, запуск теста и анализ фактического поведения.

Безопасно ли отправлять код в AI-инструменты?

Не всегда. Передавайте только необходимый контекст, исключайте секреты и оценивайте условия обработки данных.

Поделиться:
Подписывайтесь на нас:

Похожие статьи

Комментарии (0)

Загрузка комментариев...

Оставить комментарий