Привет, читатель!
В этой статье я хотел бы поделиться своим опытом и мнением о том как эффективно применять тесты в Unity и почему для игровых проектов не работает Test Driven Development (TDD) подход
Об авторе
Меня зовут Борис, я CTO в компании, занимающейся игровым аутсорсингом. Занимаюсь разработкой игр уже 14 лет, последние 5 лет на лид. позиции. За это время я участвовал в проектах как для небольших инди-студий, так и для топ-5 игровых компаний мира, а еще я основал компанию Azza Apps и мы делаем инди игру Bioneers - Факторио про живой организм
Также веду блог в Telegram, где делюсь полезными советами для Unity-разработчиков.
Ликбез для тех, кто не знаком с тестами и TDD
Тесты и точнее авто-тесты - Набор скриптов, которые автоматически запускаются и подтверждают, что логика проекта работает ожидаемо.
Test Driven Development (TDD) - Подход к разработке, когда сначала пишется тест, который описывает ожидаемое поведение кода, и только потом пишется сам код, чтобы этот тест прошёл.
На мой взгляд, Test-Driven Development — это почти идеальная модель разработки ПО.
Сначала разработчик пишет тесты, которые описывают ожидаемое поведение фичи и полностью покрывают её основные сценарии. На этом этапе тесты закономерно падают, потому что самой реализации ещё нет. В TDD это называется Red.
Затем разработчик пишет минимальный код, необходимый для прохождения тестов. Когда тесты становятся зелёными, наступает этап Green.
После этого начинается финальная стадия — Refactor: код улучшается, оптимизируется и приводится в порядок, при этом уже написанные тесты гарантируют, что поведение фичи не сломалось.
Почему же TDD не работает в Unity?
Архитектура Unity враждебна к TDD
Unity построен вокруг MonoBehaviour. А MonoBehaviour — это класс, который нельзя инстанцировать напрямую через new. Он требует сцены, GameObject-а и движка за спиной. Ни один из этих элементов недоступен в обычном C# тесте.
Хочешь протестировать компонент, который висит на GameObject? Тебе нужно либо поднять PlayMode-тест (который запускает целый экземпляр движка), либо мучительно вынести всю логику в отдельные классы, которые не наследуют MonoBehaviour. Второе — правильный архитектурный выбор, но это уже не TDD снизу вверх, это предварительное проектирование вручную, а тесты идут следом.
В настоящем TDD ты не думаешь наперёд о том, что должно быть тестируемым — архитектура вырастает из тестов. В Unity же тебе придётся заранее решить, что будет MonoBehaviour (нетестируемо), а что — чистый C# (тестируемо). Это не TDD, это дизайн с тест-совместимостью.
Обратная связь слишком медленная
TDD живёт за счёт скорости цикла. Написал тест — запустил — увидел результат за секунду. Именно это держит тебя в потоке.
Unity Test Runner ломает этот ритм. Запуск EditMode-тестов терпимый, но как только нужны PlayMode-тесты — движок перекомпилирует скрипты, заходит в Play Mode, выполняет тест, выходит. На быстрой машине это 5–15 секунд на тест. На средней — больше. При нескольких сотнях тестов это десятки минут.
Разработчик, который ждёт 10 секунд после каждой строчки кода, быстро перестаёт запускать тесты часто. А тест, который запускается редко — это не TDD
Физика, рендер и время — нетестируемая триада
Большая часть интересной логики в играх связана с тремя вещами: физикой, визуальным состоянием и временем. Все три в Unity либо недетерминированы, либо недоступны вне контекста движка.
Физика. Physics.Raycast, Rigidbody, коллайдеры — всё это работает только в PlayMode и зависит от физического движка. Ты можешь написать тест, который симулирует несколько FixedUpdate, но его поведение будет отличаться от реального в зависимости от частоты кадров, порядка обновления и платформы.
Время. Time.deltaTime в тесте равен нулю или неопределён. Любая логика с Time.time, корутинами или Invokeтребует либо специальных обёрток, либо PlayMode. Написать тест для «персонаж телепортируется через 3 секунды» прямолинейным образом нельзя.
Визуальное состояние. Анимации, переходы, шейдерные параметры — это отдельный слой, который почти невозможно покрыть модульными тестами. Интеграционный тест, который проверяет «анимация смерти проигрывается корректно», не имеет смысла без рендера.
Итерационный цикл игрового дизайна несовместим с TDD
В разработке бизнес-приложений требования относительно стабильны. «Форма отправки должна валидировать email» — это правило, которое не изменится через неделю. Тест здесь живёт долго и оправдывает затраты.
В геймдеве через три дня геймплейного плейтестинга выясняется, что механика прыжка «неприятная» и её нужно переделать. Тест, который ты написал под старую механику, теперь либо мешает, либо требует переписывания. Чем больше тестов — тем дороже каждое геймплейное изменение.
TDD предполагает, что ты знаешь, что хочешь построить, до того как начнёшь строить. Игровой дизайн устроен наоборот: ты узнаёшь, что правильно, только поиграв. Это фундаментальное противоречие.
Где TDD в Unity всё же работает
Из всего сказанного не следует, что тесты в Unity бесполезны. Они работают там, где работает TDD в принципе — на стабильных, алгоритмических частях без зависимости от движка:
Математические утилиты: расчёт траектории, интерполяция, патфайндинг
Системы прогрессии: опыт, уровни, формулы урона
Работа с данными: парсеры и сериализация
Чистая бизнес-логика: инвентарь, экономика, достижения
Отдельные модули, packages, SDK, где функционал понятен
Это важные части проекта, и именно их в первую очередь стоит покрывать тестами.
Более того, с появлением AI подход TDD становится ещё практичнее. Если у разработчика уже есть опыт работы с Test-Driven Development, то писать чистый, стабильный и предсказуемый код через TDD может быть быстрее, чем через классический подход.
AI способен за несколько минут сгенерировать набор тестов на основе требований к фиче. Задача программиста в этом случае — не писать всё с нуля, а провалидировать тесты: проверить, действительно ли они описывают нужное поведение, покрывают важные сценарии и не содержат ложных ожиданий.
Дальше разработка идёт итеративно: под каждый тест пишется своя небольшая часть кода. Такой процесс не перегружает контекст модели, позволяет проверять результат на каждом шаге и снижает риск того, что AI уедет не туда.
В итоге TDD становится не просто способом тестирования, а удобным каркасом для работы с AI. Тесты фиксируют требования, ограничивают область задачи и сразу подталкивают архитектуру в сторону более чистого, модульного и масштабируемого кода.
Когда тесты всё же имеют смысл: LiveOps и стабильные фичи
Есть один контекст, в котором писать тесты в Unity не просто оправданно, а разумно — и это не начало разработки фичи, а её зрелость. Если проект перешёл в стадию LiveOps и конкретная механика пережила несколько релизов без изменений, она де-факто стала контрактом. Она работает так, как работает, и от этого зависят игроки, аналитика и монетизация.
В этот момент написать тесты постфактум — правильное решение. Не чтобы двигать разработку вперёд, а чтобы зафиксировать поведение: «это работает именно так, и мы должны знать, если что-то изменится». Такие тесты ускоряют регрессионное тестирование перед каждым патчем и дают уверенность при рефакторинге или переносе кода.
Важно понимать: это не TDD. Здесь нет цикла красный-зелёный-рефакторинг, нет дизайна через тест. Это покрытие уже существующего, устоявшегося поведения. Методология другая, цель другая, и именно поэтому она здесь работает: требования стабильны, фича не меняется, затраты на поддержку тестов минимальны.
Вывод
TDD — это инструмент, оптимизированный под среды с быстрой обратной связью, стабильными требованиями и изолируемыми компонентами. Unity — среда с медленным запуском тестов, движковыми зависимостями на каждом шагу и итерационным дизайном, который меняет требования каждую неделю.
Это не значит «не пишите тесты в Unity». Это значит: не ждите, что TDD как методология будет работать так же, как в бэкенде или прикладном ПО. Разумный подход — тестировать то, что легко тестируется, не тестировать то, что требует героических усилий ради сомнительной пользы, и принимать это как осознанный технический выбор, а не недостаток дисциплины.
Комментарии (10)

runon
10.06.2026 10:34Хотелось бы уточнить про SDK - как бы их ловчее автоматически тестировать? Например, мобильный платеж. Ну, что игрок еще может кристалликов купить в мобильной игре, деньги со счета спишутся, кристаллики сервер начислил, клиент показал, и все хорошо.

domix32
10.06.2026 10:34Для подобного имеются dev окружения и часть с общением с третьими лицами либо байпасится либо прогоняется через тестовые же сервера с тестовыми токенами на тестовых тугриках.

ceveru
10.06.2026 10:34Стоит добавить, это к TDD не относится вообще. Это интеграционные тесты, которые находятся на другом уровне.

domix32
10.06.2026 10:34Почему никто не использует Test-Driven Development в геймдев?
Странное утверждение конечно. TDD не работает там, где нет чётких требований. Поэтому при написании собственного движка/фреймворка можно использовать TDD. Даже в "нетестируемой тройке" есть некоторый набор функциональности, который вполне можно тестировать - какие-нибудь классы векторов, конвертация юнитов и тп. Визуальный фидбэк да, сложно анализировать, хотя и тут есть некоторые варианты. То же UI тестирование вполне себе реальная вещь. Хотя писать подобные тесты ни разу не проще чем писать функциональность для тестирования.
Если речь идёт конкретно за разработку игр - там обычно есть диздок с общим видом функционала игры, а детали уточняются по мере разработки и последующих плейтестов - написать автотест на то чтобы какой-нибудь платформинг или стрельба ощущались хорошо нереально, т.к. это дизайнерский нюанс, а не функиональный. Поэтому разработка геймплея или визуального фидбэка не тестируема.

romanchikov_boris Автор
10.06.2026 10:34Не вижу противоречий.
В пункте "Где TDD в Unity всё же работает" как раз описан случай с математическими утилитами "Математические утилиты: расчёт траектории, интерполяция, патфайндинг". Кастомный движок думаю можно подвести к этому пункту
Я и не утверждаю, что тестировать UI нельзя, я сам делал тесты UI на проекте. Но через TDD сделать UI не получится
domix32
10.06.2026 10:34Никто в геймдеве - подразумевает что ни один человек в геймдеве не использует TDD. Примеры с фреймворками я уже привел. Метафункционал конкретной игры туда же. Получается, либо мы не считаем эти сферы геймдевом, либо начинаем считать вас за редиску.
Второй нюанс - не очень понятно что подразумевается под "сделать UI". Обычно UI дизайнится в условном фотошопе, пилится на элементы и собирается при помощи кода на экране. Всегда можно прикрутить возможность ткнуть в элемент на экране и сделать тест на прохождения некоторого пути по рабочим элементам - переходы между экранами обычно к этому моменту уже известны, найти интерактивный элемент на экране из кода тоже не проблема даже на резиновых layout, так что ткнуть по элементу виртуальной мышью - тоже не проблема. Единственная причина почему это непопулярно - бОльшие трудозатраты при меньшем выхлопе, если сравнивать с тестированием стабильности навигации на сайте в браузере. Это совершенно точно можно начинать с теста, просто польза от этого не слишком высокая, особенно если того UI кот наплакал.
Katasonov
А не смотрели другие популярные движки, например godot, насколько лучше там с тестами?
romanchikov_boris Автор
Нет, не смотрел ни в Unreal ни в Godot. Но от движка может зависеть только пункт
Архитектура Unity враждебна к TDD,А все остальное остается актуальным для геймдев вцеломKatasonov
Я про этот пункт и спрашивал. Более того утверждение в заголовке статьи делается о gamedev в целом, а не об юнити. Что если в других движках TDD легко интегрируется а проблема только в unity?