
В разработке игр ручное тестирование может быстро стать повторяющимся и подверженным ошибкам. Вы когда-нибудь оказывались в одном из этих, казалось бы, бесконечных циклов тестирования, работая над новой функцией или пытаясь исправить ошибку?
Автоматизировав тестирование вашего кода, вы сможете больше времени уделять креативной разработке игр и меньше — повторяющимся (но важным) задачам по контролю качества, которые гарантируют, что добавление, удаление или изменение кода не сломает ваш проект.
Unity помогает вам создавать, управлять и запускать автоматизированные тесты для ваших игр с помощью Unity Test Framework.
Unity Test Framework (UTF) позволяет вам тестировать код вашего проекта как в Edit, так и в Play режимах. Вы также можете нацелить тестовый код на различные платформы, такие как автономные, iOS или Android.
UTF устанавливается путем добавления его в ваш проект с помощью Package Manager.
Под капотом UTF интегрируется с NUnit, который является известной библиотекой тестирования с открытым исходным кодом для языков .NET.
Существует две основные категории тестов, которые вы можете написать с помощью UTF: режим редактирования и режим игры:
Тесты в Edit mode запускаются в редакторе Unity и имеют доступ как к коду редактора, так и к игровому коду. Это означает, что вы можете тестировать свои пользовательские расширения редактора или использовать тесты для изменения настроек в редакторе и входа в режим игры, что полезно для настройки значений инспектора, а затем запуска автоматизированных тестов с множеством различных настроек.
Тесты в Play mode позволяют вам проверять код вашей игры во время выполнения. Тесты обычно выполняются как корутины с использованием атрибута [UnityTest]. Это позволяет вам тестировать код, который может выполняться на нескольких кадрах. По умолчанию тесты в режиме воспроизведения будут выполняться в редакторе, но вы также можете запускать их в отдельной сборке плеера для различных целевых платформ.

Чтобы следовать за этим примером, вам нужно установить пакет Starter Assets – Third Person Character Controller из Unity Asset Store и импортировать его в новый проект.

Установите UTF через Window > Package Manager. Ищите Test Framework в Unity Registry в Package Manager. Убедитесь, что выбрана версия 1.3.3 (последняя версия на момент написания).
После установки UTF откройте файл Packages/manifest.json с помощью текстового редактора и добавьте раздел testables после зависимостей, как это:
,
"testables": [
"com.unity.inputsystem"
]
Сохраните файл. Это будет полезно позже, когда вам нужно будет ссылаться на сборку Unity.InputSystem.TestFramework для тестирования и эмуляции ввода игрока.
Вернитесь в редактор и позвольте установить более новую версию.

Нажмите Window > General > Test Runner, чтобы открыть окно редактора Test Runner.
В этой части учебника внимание будет сосредоточено на создании тестов в режиме воспроизведения. Вместо того чтобы использовать параметры Создать папку тестовой сборки в окне Test Runner, вы создадите их с помощью окна проекта.
Выделив корень папки Assets вашего проекта, щелкните правой кнопкой мыши и выберите Create > Testing > Tests Assembly Folder.
Добавляется папка проекта Tests, содержащая файл Tests.asmdef (определение сборки). Это необходимо для того, чтобы тесты могли ссылаться на ваши игровые модули и зависимости.
Код контроллера персонажа будет использоваться в тестах и также потребуется определение сборки. Далее вы настроите некоторые определения сборок и ссылки для упрощения тестирования между модулями.
Щелкните правой кнопкой мыши на папке проекта Assets/StarterAssets/InputSystem и выберите Создать > Определение сборки. Назовите его как-то описательно, например StarterAssetsInputSystem.
Выберите новый файл StarterAssetsInputSystem.asmdef и, используя инспектор, добавьте ссылку на определение сборки Unity.InputSystem. Нажмите Применить.
Щелкните правой кнопкой мыши на папке проекта Assets/StarterAssets/ThirdPersonController/Scripts и выберите Создать > Определение сборки. Назовите его как-то описательно, например ThirdPersonControllerMain.
Как и с предыдущим определением сборки, откройте ThirdPersonControllerMain в инспекторе и выберите ссылки для:
- Unity.InputSystem
- StarterAssetsInputSystem
Нажмите Применить.

Чтобы эмулировать части системы ввода, вам нужно будет сослаться на нее в ваших тестах. Кроме того, вам нужно будет сослаться на пространство имен StarterAssets в сборке, которую вы создадите для кода контроллера третьего лица.
Откройте Tests.asmdef в инспекторе и добавьте ссылку на следующие определения сборок:
- UnityEngine.TestRunner
- UnityEditor.TestRunner
- Unity.InputSystem
- Unity.InputSystem.TestFramework
- ThirdPersonControllerMain
Нажмите Применить.

Ваш первый тест охватит некоторые основы загрузки и перемещения главного персонажа из пакета Third Person Controller.
Начните с настройки нового проекта с простой сценой тестовой среды и ресурсом Prefab персонажа для работы.
Откройте сцену с именем Assets/StarterAssets/ThirdPersonController/Scenes/Playground.unity и сохраните ее копию, используя меню File > Save As по этому новому пути: Assets/Scenes/SimpleTesting.unity
Если вы заметили розовые материалы в игровом окне, используйте Конвертер рендеринга, чтобы обновить материалы с встроенного рендеринга на универсальный рендеринг (URP). Смотрите эту статью для быстрого обзора.
Создайте новую папку в папке активов вашего проекта с именем Resources. Примечание. Имя папки "Resources" здесь важно, чтобы можно было использовать метод Unity Resources.Load().
Перетащите объект GameObject PlayerArmature в окне сцены в новую папку Resources и выберите создание Original Prefab, когда будет предложено. Переименуйте актив Prefab в Character.
Это будет базовый Prefab персонажа, используемый в ваших тестах в дальнейшем.
Удалите объект GameObject PlayerArmature из новой сцены SimpleTesting и сохраните изменения в сцене.
На последнем этапе первоначальной настройки теста перейдите в File > Build Settings и выберите Добавить открытые сцены, чтобы добавить сцену Scenes/SimpleTesting в настройки сборки.
Выберите папку Tests в папке Project Assets. Щелкните правой кнопкой мыши и выберите Создать > Тестирование > Скрипт теста C#.
Назовите новый скрипт CharacterTests. Откройте скрипт в вашей IDE, чтобы подробнее его рассмотреть.
Два метода-заглушки предоставлены с исходным файлом класса, демонстрируя некоторые основы тестирования.
Далее вы убедитесь, что тесты загружают игровую сцену с фокусом на тестировании. Это должна быть сцена, содержащая минимально необходимое для тестирования системы или компонента, на котором вы сосредоточены.
Обновите класс CharacterTests, чтобы добавить два новых using оператора и реализовать класс InputTestFixture:
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
public class CharacterTests : InputTestFixture
Добавьте два приватных поля в верхнюю часть класса CharacterTests:
GameObject character = Resources.Load("Character");
Keyboard keyboard;
Поле character будет хранить ссылку на префаб Character, загруженный из папки Resources. Keyboard будет хранить ссылку на устройство ввода Keyboard, предоставляемое InputSystem.
Переопределите метод Setup() базового класса InputTestFixture, предоставив свой собственный в классе CharacterTests:
public override void Setup()
{
SceneManager.LoadScene("Scenes/SimpleTesting");
base.Setup();
keyboard = InputSystem.AddDevice();
var мышь = InputSystem.AddDevice();
Нажмите(мышь.rightButton);
Отпустите(мышь.rightButton);;
}
Метод Setup() выполняет метод Setup() базового класса, а затем настраивает ваш собственный класс CharacterTests, загружая тестовую сцену и инициализируя устройство ввода клавиатуры.
Ввод мыши добавляется исключительно для того, чтобы контроллер третьего лица начал получать ввод от симулированного/виртуального устройства клавиатуры. Это почти как действие «установить фокус».
Для вашего первого теста вы создадите персонажа из префаба и убедитесь, что он не равен null. Добавьте следующий метод в ваш класс тестов:
[Test]
public void TestPlayerInstantiation()
{
GameObject characterInstance = GameObject.Instantiate(character, Vector3.zero, Quaternion.identity);
Assert.That(characterInstance, !Is.Null);
}
Пока вы там, возможно, вы захотите очистить методы тестов шаблона образца. Удалите методы CharacterTestsSimplePasses и CharacterTestsWithEnumeratorPasses.

Сохраните скрипт и вернитесь в окно Test Runner в редакторе. Выделите тест TestPlayerInstantiation и нажмите Запустить выбранный.
Зеленая галочка обозначает успешное прохождение теста. Вы подтвердили, что персонаж может быть загружен из ресурсов, создан в тестовой сцене и не равен null в этот момент.
Вы могли заметить, что аннотация [Test] использовалась для этого теста вместо аннотации [UnityTest]. Атрибут UnityTest позволяет корутинам выполнять тесты на протяжении нескольких кадров. В этом случае вам просто нужно создать персонажа и подтвердить, что он был загружен.
В общем, вы должны использовать атрибут NUnit Test вместо атрибута UnityTest в режиме редактирования, если только вам не нужно выдавать специальные инструкции, пропустить кадр или подождать определенное время в режиме воспроизведения.

Далее вы будете использовать UnityTest, когда подтвердите, что удерживание клавиши управления вперед перемещает персонажа вперед.
Добавьте новый тестовый метод, приведенный ниже, в ваш класс CharacterTests.
Появились два новых вспомогательных метода тестирования: Press() и Release(). Оба предоставлены базовым классом InputTestFixture и помогают вам, эмулируя нажатие и отпускание управления InputSystem.
Метод TestPlayerMoves() выполняет следующее:
Создает экземпляр персонажа из префаба персонажа в месте (X: 0, Y: 0, Z: 0)
Нажимает клавишу стрелки вверх на виртуальной клавиатуре на 1 секунду, затем отпускает ее
Ждет еще 1 секунду (чтобы персонаж замедлился и остановился)
Подтверждает, что персонаж переместился на позицию по оси Z больше 1.5 единиц.
Сохраните файл, вернитесь к Test Runner и запустите новый тест.

Далее вы протестируете пользовательский скрипт Monobehaviour, добавив простой компонент Player Health.
Создайте новый скрипт в Assets/StarterAssets/ThirdPersonController/Scripts. Назовите его PlayerHealth.
Откройте скрипт в вашей IDE и замените содержимое на код, предоставленный ниже.
Здесь добавлено много нового кода. Вкратце, этот скрипт определит, находится ли персонаж игрока в состоянии падения. Если земля будет ударена один раз в состоянии падения, здоровье персонажа уменьшится на 10%.
Найдите префаб персонажа в Assets/Resources. Откройте префаб и добавьте новый компонент скрипта PlayerHealth.
Далее вы будете использовать тестовую сцену, чтобы подтвердить, что здоровье игрока падает после падения с края.
Используя атрибут [UnityTest], вы можете написать тест в режиме игры, который проверяет урон от падения. При падении более 0,2 секунды игрок должен получить 0,1f урона (эквивалент 10% от максимального здоровья).
В сцене SimpleTesting вы увидите лестницу, ведущую к краю. Это тестовая платформа, на которой нужно спавнить персонажа и тестировать скрипт PlayerHealth.
Снова откройте CharacterTests.cs и добавьте новый метод теста с именем TestPlayerFallDamage:
[UnityTest]
public IEnumerator TestPlayerFallDamage()
{
// спавнить персонажа в достаточно высоком месте в тестовой сцене
GameObject characterInstance = GameObject.Instantiate(character, new Vector3(0f, 4f, 17.2f), Quaternion.identity);
// Получить ссылку на компонент PlayerHealth и подтвердить, что здоровье полное (1f)
var characterHealth = characterInstance.GetComponent();
Assert.That(characterHealth.Health, Is.EqualTo(1f));
// Сойти с края и ждать падения
Нажмите(keyboard.upArrowKey);
yield return new WaitForSeconds(0.5f);
Отпустите(keyboard.upArrowKey);
yield return new WaitForSeconds(2f);
// Убедитесь, что 1 очко здоровья было потеряно из-за урона при падении
Assert.That(characterHealth.Health, Is.EqualTo(0.9f));
}
Вам также нужно будет добавить ссылку using на пространство имен StarterAssets в самом верху файла класса:
using StarterAssets;
Тест выше следует типичному arrange, act, assert (AAA) шаблону, который обычно встречается в тестировании:
Секция Assert проверяет, что действие тестируемого метода ведет себя так, как ожидалось.
Далее вы протестируете пользовательский скрипт Monobehaviour, добавив простой компонент Player Health.
Создайте новый скрипт в Assets/StarterAssets/ThirdPersonController/Scripts. Назовите его PlayerHealth.
Откройте скрипт в вашей IDE и замените содержимое на код, предоставленный ниже.
Здесь добавлено много нового кода. Вкратце, этот скрипт определит, находится ли персонаж игрока в состоянии падения. Если земля будет ударена один раз в состоянии падения, здоровье персонажа уменьшится на 10%.
Найдите префаб персонажа в Assets/Resources. Откройте префаб и добавьте новый компонент скрипта PlayerHealth.
Далее вы будете использовать тестовую сцену, чтобы подтвердить, что здоровье игрока падает после падения с края.
Используя атрибут [UnityTest], вы можете написать тест в режиме игры, который проверяет урон от падения. При падении более 0,2 секунды игрок должен получить 0,1f урона (эквивалент 10% от максимального здоровья).
В сцене SimpleTesting вы увидите лестницу, ведущую к краю. Это тестовая платформа, на которой нужно спавнить персонажа и тестировать скрипт PlayerHealth.
Снова откройте CharacterTests.cs и добавьте новый метод теста с именем TestPlayerFallDamage:
[UnityTest]
public IEnumerator TestPlayerFallDamage()
{
// спавнить персонажа в достаточно высоком месте в тестовой сцене
GameObject characterInstance = GameObject.Instantiate(character, new Vector3(0f, 4f, 17.2f), Quaternion.identity);
// Получить ссылку на компонент PlayerHealth и подтвердить, что здоровье полное (1f)
var characterHealth = characterInstance.GetComponent();
Assert.That(characterHealth.Health, Is.EqualTo(1f));
// Сойти с края и ждать падения
Нажмите(keyboard.upArrowKey);
yield return new WaitForSeconds(0.5f);
Отпустите(keyboard.upArrowKey);
yield return new WaitForSeconds(2f);
// Убедитесь, что 1 очко здоровья было потеряно из-за урона при падении
Assert.That(characterHealth.Health, Is.EqualTo(0.9f));
}
Вам также нужно будет добавить ссылку using на пространство имен StarterAssets в самом верху файла класса:
using StarterAssets;
Тест выше следует типичному arrange, act, assert (AAA) шаблону, который обычно встречается в тестировании:
Секция Arrange метода юнит-теста инициализирует объекты и устанавливает значение данных, которые передаются в тестируемый метод.
Секция Act вызывает тестируемый метод с подготовленными параметрами. В этом случае вызов тестируемого метода осуществляется через физическое взаимодействие, когда игрок ударяется о землю после падения.
Секция Assert проверяет, что действие тестируемого метода ведет себя так, как ожидалось.

Вернувшись в редактор, запустите новый тест. Запуская в режиме игры, вы увидите, как персонаж идет к краю, падает (превышая порог в 0,2 секунды для классификации падения) и получает урон после удара о землю.
Тесты служат не только для проверки того, что изменения в коде не нарушают функциональность, но также могут служить документацией или указателями, чтобы помочь разработчикам подумать о других аспектах игры при настройке параметров.

Как упоминалось ранее, запуск тестов в режиме игры в Test Runner по умолчанию выполняет их в режиме игры с использованием Unity Editor. Вы также можете изменить их для запуска в автономном игроке.
Используйте выпадающий список Run Location в окне Test Runner, чтобы переключить тесты на запуск в сборках автономного игрока.
Как только вы начали создавать набор тестов, следующим шагом будет автоматический запуск их после завершения сборок. Автоматизированные модульные и интеграционные тесты, которые выполняются после сборки, полезны для выявления регрессий или ошибок как можно раньше. Они также могут выполняться как часть удаленной автоматизированной системы сборки в облаке.
Часто вы захотите сохранить результаты выполнения тестов в пользовательском формате, чтобы результаты могли быть поделены с более широкой аудиторией. Чтобы сохранить результаты тестов вне редактора Unity, вам нужно будет разделить процессы сборки и выполнения.
Создайте новый скрипт в папке вашего проекта Tests с именем SetupPlaymodeTestPlayer.
Класс SetupPlaymodeTestPlayer реализует интерфейс ITestPlayerBuildModifier. Вы будете использовать это, чтобы переопределить и "подключиться" к методу ModifyOptions, который получает параметры игрока сборки и позволяет вам их изменить.
using System.IO;
using UnityEditor;
using UnityEditor.TestTools;
[assembly: TestPlayerBuildModifier(typeof(SetupPlaymodeTestPlayer))]
public class SetupPlaymodeTestPlayer : ITestPlayerBuildModifier
{
public BuildPlayerOptions ModifyOptions(BuildPlayerOptions playerOptions)
{
playerOptions.options &= ~(BuildOptions.AutoRunPlayer | BuildOptions.ConnectToHost);
var buildLocation = Path.GetFullPath("TestPlayers");
var fileName = Path.GetFileName(playerOptions.locationPathName);
if (!string.IsNullOrEmpty(fileName))
buildLocation = Path.Combine(buildLocation, fileName);
playerOptions.locationPathName = buildLocation;
return playerOptions;
}
}
Этот пользовательский скрипт модификатора сборки Player выполняет следующее, когда тесты запускаются в режиме воспроизведения (Место выполнения: На игроке):
Отключает автоматический запуск для собранных игроков и пропускает опцию игрока, которая пытается подключиться к хосту, на котором она работает
Изменяет расположение пути сборки на выделенный путь внутри проекта (TestPlayers)
С этим завершено, теперь вы можете ожидать, что сборки будут находиться в папке TestPlayers, когда они закончат сборку. Это завершает изменения сборки и разрывает связь между сборкой и запуском.
Далее вы реализуете отчетность о результатах. Это позволит вам записывать результаты тестов в пользовательское место, готовое для автоматической генерации отчетов и публикации.
Создайте новый скрипт в папке вашего проекта Tests с именем ResultSerializer (предоставлено ниже). Этот класс будет использовать ссылку на сборку TestRunCallback и реализует интерфейс ITestRunCallback.
Эта реализация ITestRunCallback включает в себя настроенный метод RunFinished, который настраивает сборку игрока с тестами для записи результатов тестов в XML-файл с именем testresults.xml.

С SetupPlaymodeTestPlayer.cs и ResultSerializer.cs в совокупности, процессы сборки и запуска теперь разделены. Запуск тестов будет выводить результаты в testresults.xml, расположенный в пути Application.persistentDataPath платформы игрока location.
Чтобы использовать некоторые из типов в этих классах хуков, вам нужно будет добавить дополнительную ссылку на Tests.asmdef. Обновите его, чтобы добавить ссылку на определение сборки UnityEditor.UI.EditorTests.
Запуск тестов в игроке теперь даст выход сборки игрока под вашим проектом в папке TestPlayers и файл testresults.xml в расположении Application.persistentDataPath.

Курс Unity Test Framework
Пакет Test Framework включает в себя курс тестирования, содержащий образцы упражнений, чтобы помочь вам узнать больше о тестировании с Unity. Не забудьте получить файлы проекта для курса, используя Диспетчер пакетов.
Используя Менеджер пакетов > Пакеты: Unity Registry > Тестовый фреймворк, найдите выпадающий список образцов и импортируйте упражнения курса.
Упражнения будут импортированы в ваш проект и расположены в Assets/Samples/Test Framework. Каждый образец включает папку с упражнениями, над которыми вы будете работать, а также решение, с которым вы можете сравнить свою работу по мере выполнения.
QA вашего кода с UTF
Этот доклад Unite Copenhagen о UTF более подробно рассматривает и предлагает некоторые другие интересные варианты использования для настройки тестов. Обязательно ознакомьтесь с ним, чтобы увидеть, что еще возможно.
Отладка в Unity
Ускорьте свой рабоч процесс отладки в Unity с помощью статей о:
- Microsoft Visual Studio 2022
- Microsoft Visual Studio Code
Расширенные технические электронные книги
Unity предоставляет ряд расширенных руководств, чтобы помочь профессиональным разработчикам оптимизировать код игры. Создайте руководство по стилю C#: Пишите более чистый код, который масштабируется собирает советы от экспертов отрасли о том, как создать руководство по стилю кода, чтобы помочь вашей команде разработать чистую, читаемую и масштабируемую кодовую базу.
Еще одно популярное руководство среди наших пользователей - это 70+ советов по повышению продуктивности с Unity. Оно наполнено советами по экономии времени, чтобы улучшить ваш повседневный агрегированный рабоч процесс с Unity 2020 LTS, включая советы, которые даже опытные разработчики могли упустить.
Документация
Изучите последний API TestRunner более подробно, узнайте о других пользовательских атрибутах UTF и откройте для себя дополнительные жизненные циклы, в которые можно подключиться с помощью UTF документации.
Найдите все расширенные электронные книги и статьи Unity в центре лучших практик Unity.