Мы ожидаем, что unit-тесты проверяют корректность изменённой логики и помогают выявлять непреднамеренные изменения в поведении приложения. При разработке с помощью AI также важно проверять, что функциональность за пределами объёма задачи осталась нетронутой.
Проверка того, что новая функция работает, - лишь часть работы. Нужно также убедиться, что изменение не нарушило существующие правила приложения.
Что должны защищать unit-тесты
Unit-тесты проверяют поведение отдельных частей кода. Они также служат защитой от регрессий - ошибок, появляющихся из-за изменения поведения, которое раньше работало.
Эта защита особенно ценна для кода, сгенерированного AI. AI может выполнить конкретное требование и при этом изменить логику, которая должна была остаться нетронутой.
Хорошо продуманные тесты помогают определить границы изменения:
Это поведение мы хотим изменить. Эти правила должны продолжать выполняться.
Тестируйте с учётом риска и реальных зависимостей
Нам не нужно автоматически писать отдельный тест для каждого геттера, сеттера или простого класса данных.
Тест, который просто повторяет реализацию, может увеличить количество тестов, не добавив особой ценности. Он также создаёт дополнительную работу по сопровождению при дальнейших изменениях.
Практическое правило таково:
Для конкретного изменения сосредоточьтесь на изменённом поведении и тех частях приложения, которые от него зависят. Объём тестирования определяйте исходя из потенциального влияния.
Для простых методов без логики принятия решений отдельный unit-тест может быть не нужен, если другие тесты адекватно покрывают их поведение.
Однако одной лишь простоты недостаточно, чтобы считать, что AI не ошибётся. Даже однострочный метод может определять цену заказа или права доступа пользователя.
Прежде чем добавлять тест, задайте три вопроса:
- Какое поведение меняется в этой задаче?
Мы проверяем, что изменение соответствует требованиям.
- Какие правила и зависимые компоненты должны остаться нетронутыми?
Мы ищем места, где изменение может вызвать регрессию.
- Поймает ли тест реальную ошибку?
Мы проверяем ожидаемое поведение, а не просто копируем реализацию.
Тесты должны быть связаны с бизнес-логикой
Самые ценные unit-тесты защищают конкретные правила приложения.
Например, для метода расчёта скидки недостаточно проверить, что он возвращает число. Нужно знать, выполняются ли по-прежнему такие правила:
скидка не превышает допустимый предел;
итоговая цена не опускается ниже нуля;
клиент, не имеющий права на скидку, платит полную цену;
расчёт следует определённым правилам округления.
Именно связь между методом и бизнес-правилом придаёт тесту смысл.
Реализация может измениться. Правило, находящееся вне предполагаемого объёма задачи, должно остаться нетронутым.
Как к этому подходит AITM
AITM связывает разработку с помощью AI с контекстом проекта, контрактами и зависимостями между разными частями приложения.
Перед реализацией architect определяет, что должно измениться, как связаны соответствующие части и какие правила должны остаться нетронутыми. Затем шаг тестирования использует эту информацию.
Ключевой вопрос, таким образом, не только в том, может ли AI написать тест. Он в том, знает ли AI, что тест должен защищать и зачем.
Рассмотрим изменение DiscountService.calculateDiscount(). Если контракт с помощью dependsOnModules фиксирует, что от расчёта скидки зависит также OrderSummary.render(), у шага тестирования есть основание проверить влияние и на сводку заказа.
Сам расчёт можно проверить unit-тестом. Для проверки того, как расчёт работает вместе со сводкой заказа, может больше подойти интеграционный тест.
Таким образом, тесты проектируются вокруг реальных зависимостей и рисков конкретного изменения.
Десять тестов для одной задачи, две тысячи для другой
Не каждой задаче нужен одинаковый объём тестирования.
Для иллюстрации: в проекте с 32 467 тестами небольшое изменение может потребовать запуска десяти релевантных тестов. Изменение общей бизнес-логики может потребовать двух тысяч.
Цель целевого тестирования - выбрать тесты, покрывающие изменённое поведение и его зависимости. Это может сократить цикл обратной связи и сфокусировать проверку на рисках задачи.
Более широкие регрессионные проверки или полный набор тестов по-прежнему уместны при обширных изменениях или перед новым релизом.
Количество запускаемых тестов должно соответствовать влиянию изменения.
Когда тест падает, нужно понять почему
Падающий тест не всегда указывает на одну и ту же проблему. Нужно различать такие ситуации:
в реализацию была внесена ошибка;
изменение непреднамеренно нарушило существующее бизнес-правило;
новая функция намеренно изменила ожидаемое поведение, и тест нужно обновить.
Требования задачи, контракты и описания бизнес-логики дают контекст для такой оценки.
Если требование законно изменилось, соответствующий тест тоже должен измениться. Если AI нарушил правило, которое должно было остаться нетронутым, реализацию нужно исправить.
Простое изменение теста ради того, чтобы он снова проходил, может скрыть реальную ошибку.
Unit-тесты - первый уровень защиты
У каждого уровня тестирования своя роль:
Unit-тесты проверяют отдельные части логики.
Интеграционные тесты проверяют, как модули и системы работают вместе.
E2E-тесты проверяют полные пользовательские сценарии в работающем приложении.
Эти уровни дополняют друг друга. Каждый ловит разные типы ошибок и помогает проверить изменение с другой стороны.
Поэтому при разработке с помощью AI мы проверяем две вещи: выполнена ли задача и осталось ли нетронутым поведение за пределами её предполагаемого объёма.
Связывание требований задачи, бизнес-логики, зависимостей и тестов - важная часть оркестрации AITM.

Напр. unit-тесты
Узнайте больше на https://www.aitm.cz
#AITM #UnitTesting #SoftwareTesting #AI #SoftwareDevelopment