
Давайте будем честны: как Unity‑разработчики, мы все пишем код, который может содержать ошибки. Это касается и меня, и вас, и даже искусственного интеллекта.
Многие разработчики программного обеспечения считают модульное (или unit) тестирование важнейшим инструментом для раннего выявления и предотвращения регрессий. Но действительно ли оно эффективно в контексте разработки Unity‑проектов?
В этой статье я поделюсь с вами нашим опытом внедрения тестов в Virtual Maker. Мы рассмотрим разницу между модульными, интеграционными и сквозными тестами, а также обсудим, почему вам не следует (по моему мнению) прибегать к последним в ваших проектах.
Затем мы углубимся в код и разберемся, как писать тесты с использованием фреймворка NUnit в Unity. Наконец, мы узнаем, как запускать тесты из командной строки и использовать GitHub Actions для полной автоматизации процесса тестирования.
Наш подход к модульному тестированию в Virtual Maker
В Virtual Maker мы уделяем модульному тестированию наших плагинов для Unity особое внимание. Это позволяет нам быть уверенными в их работоспособности в ряде различных сценариев.
Например, в 3D‑макетах Flexalon мы тщательно тестируем каждый компонент, применяя разнообразные конфигурации и пограничные случаи. Аналогично, в Proxima Inspector мы проверяем протокол взаимодействия между Unity и браузером, чтобы убедиться, что для каждого типа компонента и игрового объекта отправляются правильные данные.
3D‑макеты Flexalon предоставляют разработчикам возможность упорядочивать 3D‑объекты в виде списков, сеток, кругов и других структур.
Модульные тесты не только гарантируют корректную работу во всех пограничных случаях, но и помогают нам избежать регрессий. Каждый раз, когда мы исправляем ошибки или добавляем новые функции, мы неизбежно сталкиваемся с новыми багами. Модульные тесты позволяют нам выявлять и исправлять эти ошибки до того, как они станут проблемами для пользователей.

Чтобы своевременно отлавливать эти ошибки, мы настроили наши тесты на автоматический запуск каждый раз, когда создаем пулл‑реквест в GitHub. Благодаря этому вероятность того, что ошибка будет обнаружена до того, как изменения попадут в релиз, намного выше.
Однако не все тесты одинаковы. На моей предыдущей работе в Microsoft мы потратили много времени на написание тестов, которые в итоге не выявляли ошибки. Более того, мы создавали тесты, которые были настолько хрупкими, что тратили больше времени на отладку и исправление самих тестов, чем на непосредственную работу над продуктом.
Так что же делает один тест хорошим, а другой — плохим?
Типы тестов
Часто различие между хорошим и плохим тестом заключается в его охвате. Задайте себе вопрос: сколько компонентов должны работать корректно, чтобы тест был пройден?
Модульные тесты: Изолированное тестирование отдельного метода или класса.
Интеграционные тесты: Тестирование корректности совместной работы нескольких компонентов.
Сквозные тесты: Проверка игровых функций на предмет соответствия ожидаемому поведению в максимально возможном приближении к перспективе игрока.
Модульное тестирование
Сторонники модульного тестирования считают, что количество тестов должно быть небольшим, а каждый тест должен проверять отдельный метод или класс в изоляции. Эти тесты быстро запускаются и легко поддаются отладке, что особенно полезно для сложных функций, таких как математические.
Например, в Proxima Inspector есть класс CircularList
, который хранит логи Unity, чтобы вы могли просматривать прошлые логи, подключив инспектор. Заставить этот класс работать так, как мы хотели, было достаточно сложно, поэтому мы написали несколько модульных тестов.
[Test]
public void EnumerableWrap()
{
var list = new CircularList<int>(2); // Создает циклический список размером в 2 элемента
list.Add(1);
list.Add(2);
list.Add(3);
Assert.AreEqual(3, list.ItemsAdded);
var items = list.ToList();
Assert.AreEqual(2, items.Count);
Assert.AreEqual(2, items[0]);
Assert.AreEqual(3, items[1]);
}
Этот тест проверяет, происходит ли циклический перенос, когда класс CircularList
достигает своей емкости. Он добавляет в список три элемента, затем проверяет, содержит ли список только последние два элемента.
Интеграционное тестирование
Модульное тестирование с его четкой нацеленностью — это эффективный способ проверки сложных функций и классов. Однако зачастую его оказывается недостаточно. В Flexalon большинство серьезных ошибок возникают во взаимодействии между различными компонентами платформы.
В этом случае нам следует подумать о том, как протестировать пакет Flexalon как изолированный компонент.
Как мы можем реализовать такой тест? Он должен включать в себя следующие шаги:
Создание сцены.
Добавление нескольких gameObject»ов с компонентами Flexalon.
Запуск макета Flexalon.
Примечание 1: Вы можете использовать «платформу модульного тестирования» для написания интеграционных тестов или даже сквозных тестов. Не смотри на меня так, не я это придумал.
Примечание 2: «Интеграционное тестирование» также может подразумевать взаимодействие между различными модулями, процессами или даже распределенными компьютерами. В данном контексте я использую этот термин для описания масштаба теста, который охватывает большую область, чем отдельный класс или метод. Например, это может быть тестирование целого пакета или библиотеки.
Вот пример реального теста из Flexalon:
[Test]
public void FillChild()
{
// Создание и настройка Flexible-макета
var flex = CreateFlex();
var flexObj = flex.GetComponent<FlexalonObject>();
flexObj.Width = 3;
// Добавление в макет дочернего элемента
var child = CreateCube(flex.transform);
var obj = child.AddComponent<FlexalonObject>();
obj.WidthOfParent = 0.5f;
// Добавление в макет еще одного дочернего элемента
var child2 = CreateCube(flex.transform);
// Обновление макета
Update();
// Проверка результатов
AssertTransform(flex.transform);
AssertTransform(child.transform, new Vector3(-0.5f, 0, 0));
AssertTransform(child2.transform, new Vector3(0.5f, 0, 0));
}
Поскольку подобных тестов много, мы написали вспомогательные методы для упрощения общего функционала: создания компонентов Flexalon, обновления макета и проверки результатов.
Важно отметить, что эти тесты выполняются в EditMode. Нам не требуется играть в игру для их запуска, и нам не нужно выполнять какие‑либо асинхронные действия. Flexalon был разработан с учетом простоты тестирования. Вызывая метод Update(), мы заставляем Flexalon немедленно обрабатывать все обновления макета, хотя обычно он ожидает следующего кадра.
Это приводит нас к одному важному правилу: разрабатывайте компоненты так, чтобы их можно было легко тестировать независимо друг от друга. Если ваши тесты не будут быстрыми и надежными, они быстро утратят всякую пользу.
Сквозное тестирование
В рамках сквозного тестировании мы стремимся проверять продукт так, как его использовал бы пользователь. Обычно это подразумевает некоторое моделирование входных данных, чтобы тест мог действовать как игрок, проходить игру и затем проверять результаты.
Проводя сквозные тесты, вы можете быть уверены, что продукт действительно работает так, как вы ожидаете. Зачем вообще тратить время на проверку каждого отдельного элемента, когда можно просто воспроизвести опыт реального игрока?
Вопрос закономерный, но не все так просто.
На практике сквозные тесты часто оказываются медленными, хрупкими и сложными в обслуживании.
Давайте рассмотрим простой пример. Допустим, вы хотите проверить, может ли игрок изменять громкость. Для этого сначала нужно открыть главное меню, а затем переместить ползунок громкости. В чем заключаются проблемы?
Медленно: Если анимация открытия главного меню занимает 2 секунды, то тесту нужно будет ждать 2 секунды. Умножьте это на количество тестов, которые должны открывать главное меню.
Хрупко: Что, если выполнение анимации займет немного больше времени из‑за медленной работы тестового компьютера? Хоть мы и не задавались целью тестировать производительность, тест все‑равно будет не пройден. Что, если положение регулятора громкости меняется в зависимости от размера экрана? В конце концов, вы обнаружите, что из кожи вон лезете, пытаясь стабилизировать среду для этого простого теста.
Сложно поддерживать: Предположим, дизайнер решает изменить анимацию главного меню на 3 секунды. Теперь вам нужно будет обновить каждый тест, зависящий от главного меню, чтобы они ждали 3 секунды вместо 2.
Умные разработчики могут попытаться решить эти проблемы, добавив функции, которые сделают тесты более быстрыми и надежными. Например, вместо того чтобы ждать 2 секунды, пока анимация воспроизведется, мы можем добавить в игру специальное событие open-main-menu-completed
, которого тест сможет дождаться. Затем мы можем ускорить воспроизведение анимаций для тестов в десять раз, чтобы все анимации завершались за 0,2 секунды.
Хоть намерения здесь и благие, логика такова, что сейчас разработчики тратят больше времени на отладку тестов и поддержание тестовой инфраструктуры, вместо того чтобы улучшать продукт. В одном из моих прошлых проектов мы потратили больше времени на решение проблем с тестами, чем на улучшение продукта.
Ладно, ладно. Так что, нам вообще НЕ НУЖНО писать сквозные тесты?
Скорее всего, да.
Вместо этого проектируйте свое приложение таким образом, чтобы сложные части можно было тестировать по отдельности. Лучше оставьте сквозное тестирование тестировщикам или искусственному интеллекту, в зависимости от конкретной ситуации.
Написание тестов в Unity с использованием NUnit
Unity предлагает встроенную платформу модульного тестирования под названием NUnit. Чтобы приступить к работе, достаточно установить пакет NUnit из менеджера пакетов Unity.
Перейдите в меню «Window» и выберите пункт «Package Manager».
Из выпадающего списка в окне «Package Manager» выберите «Unity Registry».
Найдите в списке доступных пакетов «NUnit» и нажмите «Install».
EditMode и PlayMode тесты
В Unity есть два типа тестов: EditMode‑тесты и PlayMode‑тесты.
EditMode‑тесты: Эти тесты выполняются непосредственно в редакторе Unity и идеально подходят как для модульных, так и для интеграционных тестов. По возможности, старайтесь использовать EditMode‑тесты.
PlayMode‑тесты: Эти тесты могут выполняться в редакторе Unity в режиме Play или при автономном запуске. Однако их следует использовать в последнюю очередь, поскольку они выполняются медленнее и менее надежны. По возможности старайтесь обновлять свои компоненты для поддержки EditMode‑тестов вместо того, чтобы писать PlayMode‑тесты.
EditMode-тесты
Для демонстрации мы будем использовать простой компонент под названием SimpleCircleLayout
, который размещает свои дочерние элементы по кругу вокруг своего центра.
Этот компонент представляет собой сильно упрощенную версию FlexalonCircleLayout, который уже покрыт тестами аналогичными тем, которые мы напишем здесь.
using UnityEngine;
public class SimpleCircleLayout : MonoBehaviour
{
public float Radius = 2;
public void LayoutChildren()
{
float angle = 0;
foreach (Transform child in transform)
{
float x = Radius * Mathf.Cos(angle);
float y = Radius * Mathf.Sin(angle);
child.position = transform.position + new Vector3(x, y, 0);
angle += 2 * Mathf.PI / transform.childCount;
}
}
}
Создаем определение сборки для EditMode-тестов
Прежде чем мы сможем писать тесты, нам нужно создать специальную сборку, в которой будут работать наши тесты.
Прежде чем мы приступим к написанию тестов, нам необходимо создать специальную сборку (assembly), в которой будут выполняться наши тесты.
Для этого откройте «Window» > «General» и выберите пункт «Test Runner».
Если в вашем проекте пока нет тестов, вы увидите следующее:

3.Нажмите «Create EditMode Test Assembly Folder». Это действие создаст новую папку под названием «Tests», в которой будет находиться файл определения сборки (assembly definition). Вы можете переименовать эту папку по своему усмотрению.
4.Для проведения тестирования ваш код должен быть размещен в собственном файле определения сборки. Если ваш скрипт находится в вашем основном проекте, кликните правой кнопкой мыши по папке «Assets» во вкладке проекта и выберите опцию «Create» > «Assembly Definition».

5. Перетащите определение вашей сборки в список ссылок определения тестовой сборки.
Вот окончательный вид определения тестовой сборки для Flexalon:

Пишем свой тестовый класс
Мы подготовили тестовую сборку и можем приступить к написанию тестов. Создайте новый файл с именем SimpleCircleLayoutTests.cs
в папке с тестами, рядом с файлом определения сборки.
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class SimpleCircleLayoutTests
{
[Test]
public void TestLayoutChildren()
{
var layout = new GameObject().AddComponent<SimpleCircleLayout>();
layout.Radius = 2;
var child1 = new GameObject().transform;
var child2 = new GameObject().transform;
var child3 = new GameObject().transform;
child1.SetParent(layout.transform);
child2.SetParent(layout.transform);
child3.SetParent(layout.transform);
layout.LayoutChildren();
TestUtil.AssertVector3Equal(new Vector3(2, 0, 0), child1.position);
TestUtil.AssertVector3Equal(new Vector3(-1, 1.73f, 0), child2.position);
TestUtil.AssertVector3Equal(new Vector3(-1, -1.73f, 0), child3.position);
}
}
В первом тесте мы создаем компонент SimpleCircleLayout
и добавляем к нему три дочерних объекта. Затем мы вызываем метод layoutChildren
и проверяем, что дочерние элементы правильно расположены по кругу вокруг центра. Наконец, мы используем класс Assert
, чтобы убедиться, что фактические позиции соответствуют ожидаемым.
Вы можете добавлять дополнительные тесты, создавая новые методы с атрибутом [Test]
. Каждый тестовый метод должен быть независимым и проверять определенный аспект компонента.
Запуск EditMode-тестов
Чтобы запустить EditMode‑тесты, перейдите в окно программы запуска тестов Unity («Window» > «General» > «Test Runner») и нажмите на «Run All». Результаты тестирования будут отображены в окне «Test Runner», где вы увидите, какие тесты пройдены, а какие завершились неудачей.
Как ни странно, вы заметите, что тесты завершаются неудачей с сообщением:
TestLayoutChildren (0.012s)
---
Expected: (-1.00, 1.73, 0.00)
But was: (-1.00, 1.73, 0.00)
---
Но почему так происходит?
Исправление тестов (равенство между Vector3 и Quaternion)
В Unity типы Vector3
и Quaternion
представляют собой значения с плавающей запятой, что может вызывать проблемы с точностью. Например, фактическое значение Y скорее всего не равно точно 1.73 — Unity обычно отображает только первые две цифры после десятичной точки.
Чтобы решить эту проблему, можно использовать вспомогательный класс для проверки, находится ли разница между двумя значениями в пределах определенной допустимой погрешности, например, 0.01.
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools.Utils;
public class TestUtil
{
private static Vector3EqualityComparer vector3Comparer = new(0.01f);
private static QuaternionEqualityComparer quaternionComparer = new(0.01f);
public static void AssertVector3Equal(Vector3 expected, Vector3 actual)
{
Assert.That(actual, Is.EqualTo(expected).Using(vector3Comparer), "Vectors are Equal");
}
public static void AssertQuaternionEqual(Quaternion expected, Quaternion actual)
{
Assert.That(actual, Is.EqualTo(expected).Using(quaternionComparer), "Quaternions are Equal");
}
}
Теперь, если мы заменим вызовы Assert.AreEqual
наTestUtil.AssertVector3Equal
, тесты будут успешно пройдены.

Setup и Teardown
В некоторых случаях удобно выполнять определенные повторяющиеся действия по настройке и деконструкции до и после каждого теста. Для этого можно использовать атрибуты [SetUp]
и [TearDown]
, которые обозначают методы, выполняемые перед и после каждого теста соответственно.
Например, предположим, что мы хотим протестировать круговой макет с различным количеством дочерних элементов.
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class SimpleCircleLayoutTests
{
private SimpleCircleLayout _layout;
[SetUp]
public void Setup()
{
_layout = new GameObject().AddComponent<SimpleCircleLayout>();
_layout.Radius = 2;
}
[TearDown]
public void Teardown()
{
GameObject.DestroyImmediate(_layout.gameObject);
}
[Test]
public void TestOneChild()
{
var child = new GameObject().transform;
child.SetParent(_layout.transform);
_layout.LayoutChildren();
TestUtil.AssertVector3Equal(new Vector3(2, 0, 0), child.position);
}
[Test]
public void TestTwoChildren()
{
var child1 = new GameObject().transform;
var child2 = new GameObject().transform;
child1.SetParent(_layout.transform);
child2.SetParent(_layout.transform);
_layout.LayoutChildren();
TestUtil.AssertVector3Equal(new Vector3(2, 0, 0), child1.position);
TestUtil.AssertVector3Equal(new Vector3(-2, 0, 0), child2.position);
}
}
В этом примере метод Setup
отвечает за создание нового компонентаSimpleCircleLayout
перед каждым тестом, а метод Teardown
— за его уничтожение после завершения теста. Это позволяет каждому тесту запускаться с чистого листа и не влиять на результаты других тестов.
Тестовые Атрибуты
Интегрированная среда тестирования Unity предлагает ряд дополнительных атрибутов, которые вы можете использовать для эффективной организации и управления тестами:
[TestFixture]
: указывает на класс, в котором содержатся тесты.[Test]
: помечает метод как тест.[SetUp]
: определяет метод, который запускается перед каждым тестом. Служит для настройки необходимых условий для проведения теста.[TearDown]
: определяет метод, который выполняется по завершению каждого теста. Этот метод отвечает за высвобождение любых ресурсов и сброс состояния, оставшихся после выполнения теста.[OneTimeSetUp]
: выполняется единожды перед запуском всех тестов в тестовом классе.[OneTimeTearDown]
: также выполняется единожды, но уже после завершения всех тестов в классе.[UnityTest]
: предназначен для PlayMode‑тестов (см. ниже). Он указывает Unity на то, что тест следует запускать как корутину.
Вообще говоря, будьте осторожны с [OneTimeSetUp]
и [OneTimeTearDown]
, так как они могут создать зависимости между тестами. Например, если мы создадим SimpleCircleLayout
в [OneTimeSetUp]
, а не в [SetUp]
, то один и тот же макет будет использоваться для всех тестов. Если один тест добавит дочерние элементы и не очистит их после себя, то следующий тест будет выполняться с уже добавленными дочерними элементами, что может привести к неожиданным результатам.
PlayMode-тесты
PlayMode‑тесты могут выполняться как в редакторе Unity в режиме Play, так и при автономном запуске. Из‑за этого PlayMode‑тесты могут быть медленными и хрупкими.
Однако есть несколько сценариев, в которых PlayMode‑тесты оправданны, особенно когда для воспроизведения требуемого поведения необходимо несколько кадров.
Например, в Flexalon есть компонент FlexalonInteractable, позволяющий игроку перетаскивать объект. Нам нужно проверить, что если игрок кликает на интерактивный объект и вытаскивает его из макета, то объект оказывается в правильном положении и макет обновляется корректно. Вот как это выглядит на практике:
https://www.virtualmaker.dev/images/blog/flexalon-grab-vr.mp4
[UnityTest]
public IEnumerator DraggableRemove()
{
var dragTarget = CreateDragTarget();
var interactable1 = CreateInteractable(dragTarget.transform);
var interactable2 = CreateInteractable(dragTarget.transform);
yield return MoveFromTo(new Vector3(0.5f, 0, 0), new Vector3(2.5f, 0, 0));
Assert.AreEqual(1, dragTarget.transform.childCount);
Assert.IsTrue(interactable1.transform == dragTarget.transform.GetChild(0));
}
Эти тесты в Flexalon действительно являются самыми медленными и хрупкими. В частности, для корректной работы вспомогательной функции MoveFromTo
потребовалось немало времени. Однако мы считаем, что эти тесты того стоят, так как они проверяют критически важную часть продукта, и покрывают множество возможных пограничных случаев.
Пример, где требуются PlayMode-тесты
Чтобы продемонстрировать, как работают PlayMode‑тесты, давайте добавим компонент RotateOnce
. Этот компонент будет проворачивать GameObject вокруг оси Z ровно один раз за определенное время.
using UnityEngine;
public class RotateOnce : MonoBehaviour
{
public float Duration = 3.0f;
private float _startTime;
private void OnEnable()
{
_startTime = Time.time;
}
private void Update()
{
float t = (Time.time - _startTime) / Duration;
transform.rotation = Quaternion.Euler(0, 0, Mathf.Lerp(0, 360, t));
}
}
Создаем определение сборки для PlayMode-тестов
PlayMode‑тесты должны находиться в отдельной от EditMode‑тестов сборке, поскольку они не могут ссылаться на пространство имен UnityEditor. Для нужно выполнить те же действия, что мы проделали в начале раздела создания определения сборки EditMode‑тестов, но на этот раз в конце нужно выбрать «Play Mode».

Основы работы с PlayMode-тестами
Теперь, когда наша сборка готова, мы можем приступить к написанию PlayMode‑тестов. В папке с тестами, рядом с файлом определения сборки, создайте новый файл с именем RotateOnceTests.cs.
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class RotateOnceTests
{
[UnityTest]
public IEnumerator TestRotateOnce()
{
var rotateOnce = new GameObject().AddComponent<RotateOnce>();
rotateOnce.Duration = 3.0f;
yield return new WaitForSeconds(1f);
TestUtil.AssertQuaternionEqual(Quaternion.Euler(0, 0, 120), rotateOnce.transform.rotation);
yield return new WaitForSeconds(1f);
TestUtil.AssertQuaternionEqual(Quaternion.Euler(0, 0, 240), rotateOnce.transform.rotation);
yield return new WaitForSeconds(1f);
TestUtil.AssertQuaternionEqual(Quaternion.Euler(0, 0, 360), rotateOnce.transform.rotation);
yield return new WaitForSeconds(1f);
// Проверяем, что происходит только одно вращение!
TestUtil.AssertQuaternionEqual(Quaternion.Euler(0, 0, 360), rotateOnce.transform.rotation);
}
}
В этом тесте мы создаем компонент RotateOnce
, который провернется один раз в течение 3 секунд. Затем мы проверим ротацию этого компонента в разные моменты времени.
Чтобы этот тест работал, нам необходимо использовать атрибут [UnityTest]
вместо [Test]
и изменить возвращаемый тип на IEnumerator
. Это позволит методу работать как корутина, и мы сможем использовать yield return
для выполнения асинхронных операций. Рекомендую вам узнать больше о корутинах в Unity.
Запуск PlayMode-тестов
Чтобы запустить PlayMode‑тесты, откройте окно программы запуска тестов Unity («Window» > «General» > «Test Runner»)и выберите параметр «PlayMode» в выпадающем списке. Нажмите на «Run All», чтобы запустить тесты. Результаты тестирования отобразятся в окне «Test Runner», где вы увидите, какие тесты пройдены, а какие завершились неудачей.

Совет: Если вы добавите инструкции Debug.Log в свой тест, они будут отображаться в результатах. Это может быть полезно при отладке неуспешных тестов.
Запуск тестов из командной строки
Запуск тестов вручную отлично подходит для небольших проектов, но по мере роста вашего проекта вам захочется автоматизировать процесс, чтобы выявлять проблемы на ранней стадии и обеспечивать стабильное качество. Unity предоставляет параметры командной строки для запуска тестов, что позволяет интегрировать их в ваш конвейер сборки или систему непрерывной интеграции.
Чтобы запустить тесты из командной строки, вам нужно использовать аргумент -runTests
, за которым должен следовать -testPlatform
, чтобы указать, в каком режиме будут проходить тесты: EditMode или PlayMode.
Unity.exe -batchmode -nographics -runTests -projectPath
"path/to/your/project" -testPlatform EditMode
Примечание: Не следует передавать флаг -quit
в командную строку, так как это приведет к завершению работы Unity перед запуском тестов. NUnit автоматически завершит работу Unity после завершения тестов.
Вы можете воспользоваться дополнительными параметрами для фильтрации тестов, которые будут запущены. Полный список аргументов командной строки можно найти в документации.
Анализ результатов тестов
После выполнения команды в корневом каталоге вашего проекта будет создан файл с именем, похожим на что вроде TestResults-638683971208353675.xml
, в котором вы можете найти результаты вашего теста. Например:
<test-case id="1305" name="Collider2DFixedAndComponent"
fullname="FlexalonAdapterTests.Collider2DFixedAndComponent"
methodname="Collider2DFixedAndComponent"
classname="FlexalonAdapterTests"
runstate="Runnable"
seed="4201476" result="Passed" start-time="2024-11-26
03:42:24Z" end-time="2024-11-26 03:42:24Z" duration="0.001536" asserts="0">
В этом примере мы видим результат теста FlexalonAdapterTests.Collider2DFixedAndComponent
с result="Passed".
Автоматизация тестов с помощью GitHub Actions
Теперь, когда мы знаем, как запускать тесты из командной строки, мы можете легко интегрировать их в любой конвейер непрерывной интеграции.
Если вы используете GitHub Actions, мы подготовили статью Автоматизация сборок Unity с помощью GitHub Actions, которая поможет вам разобраться, что к чему.
Затем вы можете обновить свой файл рабочего процесса, добавив этап для запуска тестов. Мы рекомендуем разместить его после этапа Project Validation:
name: Run Edit Mode Tests
using: buildalon/unity-action@v1
with:
build-target: ${{ matrix.build-target }}
args: -runTests -batchmode -testPlatform EditMode -testResults "${{ env.UNITY_PROJECT_PATH }}/Logs/EditMode-test-results.xml"
log-name: EditMode-Tests
Кроме того, не забудьте обновить шаг actions/upload‑artifacts, включив результаты теста в список загружаемых артефактов:
- uses: actions/upload-artifact@v4
# ...
with:
# ...
path: |
${{ github.workspace }}/**/*.xml # <- ADD THIS LINE
# ...
Заключение
Пакет Unity NUnit предоставляет мощный инструмент для написания тестов, которые помогут вам избежать ошибок в вашем проекте. Мы рассмотрели различия между модульным тестированием, интеграционным тестированием и сквозным тестированием, а также обсудили, когда целесообразно использовать каждое из них.
Мы также научились писать EditMode и PlayMode‑тесты в и запускать их из командной строки или в автоматическом режиме с помощью GitHub Actions.
Теперь, когда вы обладаете этими знаниями, я ожидаю от вас лучшего кода.
Вперед, к новым свершениям!
Материал подготовлен в рамках онлайн-курса "Unity Game Developer. Professional". Если вам интересно развитие в разработке на Unity, проверьте свой уровень знаний для поступления на курс — пройдите вступительный тест и получите скидку на обучение.
Больше обучающих программ смотрите в каталоге курсов.
bimba123
мне 15 лет и я думаю идти изучать программирование или нет. вы бы не могли подсказать что делать?