Привет! Сегодня хочу поделиться опытом тестирования на ML-проекте. По моему опыту, о машинном обучении говорят много, а вот о его тестировании — заметно реже. На истину в последней инстанции не претендую, но надеюсь быть полезным. Если у вас был опыт тестирования ML – буду рад обсудить в комментариях!
На всякий случай напомню: меня зовут Максим Белопросов, я QA Team Lead в компании 1221Systems и один из ответственных за направление автоматизированного тестирования.
В этой статье я хочу рассказать:
кратко о нашем ML-проекте, чтобы погрузить в контекст
с какими трудностями мы столкнулись
как решали их на практике
P.S. Я пишу с позиции тестировщика, а не ML/DS‑специалиста.
Что такое ML?

На всякий случай кратко напомню: ML (Machine Learning, машинное обучение) — это подход, при котором система учится на данных, а не по заранее прописанным правилам.
Мы предоставляем модели множество примеров, она выявляет закономерности и затем может делать прогнозы или принимать решения в новых ситуациях без прямого вмешательства человека.
Кратко о проекте
Есть такая сеть супермаркетов Spar. Каждый день каждому магазину нужно точно рассчитать объём заказа: товара должно хватить всем покупателям, но при этом нельзя допустить излишков и последующих списаний.
В этом помогает AutoOrderService — система автозаказа. Она анализирует десятки факторов: сезонность, погоду, праздники, календарные события. Например, за несколько дней до 1 сентября система фиксирует рост спроса на цветы и уже 30–31 августа прогнозирует увеличение поставок.
Почему тестирование ML сложнее обычного
Детерминизм vs вероятность
В классических системах результат детерминирован: при одинаковых входных данных мы всегда получаем один и тот же результат. Простой пример — если отпустить яблоко, оно упадёт вниз.
ML-системы работают иначе. Их поведение вероятностное: модель не «знает» ответ наверняка, а оценивает вероятность различных вариантов. Это больше похоже на бросок кубика — мы не можем предсказать конкретное число, но можем говорить о вероятностях.
Из-за этого в тестировании мы проверяем не конкретный ответ, а качество прогноза и допустимые отклонения.
Фокус смещается с кода на данные
В ML-проектах объект тестирования — не только код, но и данные.
Код — это механизм, а данные — топливо.Даже самый продвинутый алгоритм даст слабый результат, если обучался на некачественных и/или неполных данных. Поэтому проверка датасетов становится критически важной частью тестирования.
Устаревание модели (model drift)
Модель обучается на исторических данных, но реальность меняется.
Появляются новые товары, меняются покупательские привычки, случаются кризисы.Если модель не переобучать и не мониторить её качество, точность прогнозов начинает постепенно снижаться. Это называется устареванием модели — и это отдельный объект контроля в ML-тестировании.
Контекст и цена ошибки
Как мы знаем, протестировать всё невозможно. Поэтому важно управлять риском и учитывать бизнес-контекст.
Например, ошибка прогноза в 10% для дешёвого товара (например, жевательной резинки) почти незаметна. Та же ошибка для дорогой категории может обернуться существенными финансовыми потерями.
Тестирование должно учитывать не только метрики модели, но и стоимость ошибки для бизнеса.
Новые типы ошибок
Помимо классических багов в коде появляются ошибки данных:
аномалии,
некорректные источники данных,
проблемы интеграции,
и т. д.
Часто такие ошибки сложнее обнаружить, чем обычный дефект в логике программы.

Рассмотрим тестирование ML на каждом этапе разработки ПО
Анализ требований
В классическом тестировании всё относительно просто: аналитики дают нам документацию, мы изучаем её и понимаем, что делает продукт и какие у него ограничения. Наша задача – не только разобраться, но и вовремя заметить ошибки или противоречия в документации. Чем раньше нашли – тем быстрее исправили.
С тестированием ML всё сложнее. Например, заказчик говорит: «Нужно улучшить прогноз продаж товаров в магазине». Но как понять, что прогноз стал лучше? Тут нет чёткой инструкции и единственного правильного ответа.
Чтобы это оценивать, мы ввели специальные метрики:
технические (например, насколько сильно прогноз отличается от факта),
бизнес-метрики (насколько это отклонение влияет на продажи и прибыль).
Так же мы договариваемся о косвенном ожидаемом результате: например, прогноз спроса на шоколад может отличаться от реальных продаж максимум на 10%. Если больше – значит модель работает некорректно.
Планирование тестирования
В классическом тестировании после анализа требований мы пишем тестовую документацию: описываем шаги, условия и ожидаемый результат. Это нужно, чтобы потом сравнить ожидания с фактом.
В ML всё иначе — правильного ответа нет. Вместо этого мы задаём допустимые диапазоны. Например, прогноз спроса может отличаться от реальных продаж не больше чем на 10%.
Кроме того, на вход могут поступать некорректные, например аномальные, данные. Это такие ситуации, которые не отражают обычный спрос: компания скупила всё мясо для корпоратива в соседнем супермаркете, что не характерно для данного магазина. Такие данные должны отсекаться, чтобы не искажать прогноз. Поэтому мы должны тестировать в том числе некорректные данные, чтобы удостовериться, что прогноз будет верным.
Настройка окружения и подготовка данных
Следующий этап — настройка окружения и подготовка данных.
Обычно мы выбираем стенд для тестирования, устанавливаем нужное программное обеспечение и создаём тестовые данные — вручную или автоматически через скрипты.В ML всё строже: модель чувствительна к версиям библиотек. Даже небольшое отличие может изменить результат. Поэтому мы на проекте используем стандартную практику — контейнеризацию (Docker), где фиксируем версии.
Отдельная задача — защита персональных данных. Для модели нужны данные, близкие к реальным, но без риска раскрытия личной информации. Мы решаем это через хэширование: видим корректные продажи, но не можем связать их с конкретными покупателями.
Также важно учитывать дрейф данных. Со временем данные, на которых обучалась модель, могут меняться. Например, в праздничные дни продажи резко растут, и модель, обученная на «обычных» периодах, начинает ошибаться. Поэтому важно мониторить метрики, чтобы вовремя отследить, когда модель нужно обновить или дообучить.
Выполнение тестов
Этот этап – краеугольный камень тестирования. Обычно мы берём написанную тестовую документацию, проверяем функционал и фиксируем результаты прогона.
В ML этот этап осложняется отсутствием чёткого ожидаемого результата, как мы уже говорили выше. Здесь нас снова выручают метрики и диапазоны значений.
Однако важно помнить, что метрики сильно зависят от данных. В категории «шоколад» показатели могут быть хорошими, а если спуститься на конкретный бренд, например «Аленку», результаты окажутся хуже. То же самое: хлеб может прогнозироваться точно, а соусы — нет.
Чтобы это проверить, мы тестируем модель на разных типах данных. Это могут быть разные классы товаров: шоколад, хлеб, соусы. Такой подход позволяет увидеть картину не только «в среднем по больнице», но и в деталях.
Модели обучаются на больших объёмах данных, но тестировать их целиком — слишком долго и очень затратно. Поэтому мы тестируем выборку: ограниченный, но максимально разнообразный набор супермаркетов, разного размера, формата и специфики. Это быстрее и при этом даёт нам представление о качестве модели.
Важно помнить, что ошибки в ML могут быть не только в коде. Также встречаются:
Дрейф данных: когда текущие данные начинают сильно отличаться от тех, на которых обучалась модель, и точность прогноза падает.
Системные баги: ошибки на уровне инфраструктуры или интеграций. Например, если ночной процесс передачи данных о продажах из системы (Spar) задержался или «упал», то утром бизнес не получит прогноз вовремя. Это не баг модели, но для клиента результат будет тот же — прогноз не готов.
Поэтому тестирование ML требует учитывать не только качество кода, но и стабильность данных, инфраструктуры и процессов вокруг модели.
Регрессия
Это самый долгий этап, потому что нужно проверить всю систему целиком и подготовить отчёт о качестве продукта
В ML может случиться так, что одна метрика улучшилась (например, наша основная задача выполнена), а другая ухудшилась. Важно разбирать каждый такой случай: критично ли падение другой метрики сейчас или оно не связано с новым функционалом? Важно находить баланс и расставлять приоритеты между метриками.
Иногда новая модель перестаёт решать задачи, которые корректно решала старая. Чтобы этого избежать, мы создаём тестовую документацию и проверяем её перед каждым релизом — так убеждаемся, что старый функционал работает правильно.
Подведём промежуточный итог
Когда мы тестируем обычный софт, мы опираемся на документацию и требования. Это своего рода рецепт: всё расписано по шагам, а ожидаемый результат заранее известен. Тестировщик просто следует этому рецепту: проверяет, что всё приготовлено правильно, и фиксирует результат.
С ML всё иначе. ML-тестирование больше похоже на работу шеф-повара. Здесь нет точного рецепта: данные меняются, результаты могут отличаться, и систему нужно постоянно «пробовать на вкус». Тестировщик следит за тем, какие ингредиенты (данные) используются, оценивает результат по метрикам, при необходимости предлагает корректировки и решает, готова ли модель к работе. Иногда приходится экспериментировать: строгого рецепта нет, а итог всё равно должен устраивать клиента.

Плюсы тестирования ML
Мы поговорили о том, почему тестировать ML сложно. Но должны же быть у такого подхода свое преимущества? И они есть!
Полноценное A/B-тестирование
Новую модель можно запустить параллельно со старой и сравнить их работу в реальных условиях. Это позволяет понять, действительно ли новая версия работает лучше, и принимать решения на основе данных, а не интуиции.
Реалистичные данные
Для тестирования используются данные, максимально приближённые к реальным. Благодаря этому можно заранее увидеть, как модель поведёт себя в продакшене, и обнаружить проблемы до релиза.
Контроль через метрики
Качество работы модели измеряется метриками. Если показатели начинают ухудшаться, это сразу заметно — и можно вовремя принять меры: дообучить модель или пересмотреть данные.
Больше данных — больше сценариев
Большие объёмы данных позволяют проверять больше ситуаций и лучше понимать, как модель ведёт себя в разных условиях.
Проверка устойчивости к изменениям
Можно тестировать, как модель реагирует на новые условия: сезонность, аномалии, изменения спроса. Это помогает заранее выявить возможные проблемы.
Наши факапы
Все любят слушать про ошибки — у нас они тоже были.

Один параметр — грузовик молочки
Однажды система дала аномально высокий прогноз по молочным продуктам: сливочному маслу, сметане и творогу. Причина оказалась банальной — в коде сезонного алгоритма перепутали два почти одинаковых параметра: prediction_share и predict_share.
В результате в магазины приехал целый грузовик молочной продукции, а директор магазина был, мягко говоря, удивлён. Творог пришлось продавать с большой скидкой из-за короткого срока годности.
Если бы аномалию прогноза заметили на этапе тестирования, эту ситуацию можно было бы предотвратить.
Недопрогноз лавашей
Бывает и обратная ситуация — недопрогноз.
После одного из релизов система начала неправильно учитывать недельную сезонность для лавашей. Раньше пики продаж на выходных прогнозировались корректно, но после обновления спрос начал «расти» в середине недели. Так как лаваш — товар с небольшими продажами, проблему заметили не сразу.
В итоге перед выходными покупатели приходили за лавашем, а его просто не было в магазинах.Этот кейс показал, насколько важно тестирование вглубь по каждой категории низкого уровня, даже для товаров с небольшими продажами.
Когда модель «не знает», что наступил новый год
Начало 2025 года оказалось для нас непростым. Модель начала выдавать странные прогнозы по продажам. Оказалось, что она просто «не понимала», что наступил 2025 год — из-за некорректной кодировки типа данных для параметра year. Система обнаружения аномалий тоже не сработала: новые значения выходили за привычный диапазон, но защита этого не распознала.
В результате магазины получили некорректные прогнозы, а команде пришлось срочно корректировать заказы.
Этот случай показал, что в ML-тестировании важно:
проверять модель на будущих периодах и данных, которых она ещё не видела;
контролировать работу системы обнаружения аномалий.
А как вы тестируете ML-продукты? Какие лайфхаки работают у вас? И как вы мониторите дрифт данных?
Давайте делиться опытом — именно так появляются лучшие практики. Жду вас в комментариях!
