Введение в юнит-тестирование в Unity

 

Введение в юнит-тестирование в Unity

Вам любопытно, как работает юнит-тестирование в Unity? Не знаете, что такое юнит-тестирование в целом? Если вы положительно ответили на эти вопросы, то данная статья вам будет полезна. Мы рассмотрим следующие пункты:

·        что это такое

·        его польза

·        достоиства и недостатки

·        как оно работает в Unity при использовании Test Runner

·        как писать и выполнять юит-тесты, которые будут проходить проверку

Что такое юнит-тест (Unit Test)?

         Если говорить просто, то юнит-тестирование – это тестирование… юнитов.

Юнит-тест (в идеале) предназначен для тестирования отдельного «юнита» кода. Состав «юнита» может варьироваться, но важно помнить, что юнит-тестирование должно тестировать ровно один «элемент» за раз.

Юнит-тесты необходимо создавать для проверки того, что небольшой логический фрагмент кода в конкретном сценарии выполняется именно так, как вы ожидаете.

Юнит-тесты принудительно выполняют логику метода.

Пример юнит-тестов

Прежде чем мы начнём реализовывать эти юнит-тесты, нужно тщательно продумать, что делают эти тесты, и придумать для них названия.

Посмотрите на показанные ниже примеры названий юнит-тестов. Из названий должно быть понятно, что они проверяют:

UpdateNameDoesntAllowCharacterAddingToNameIfNameIsTenOrMoreCharactersInLength

UpdateNameAllowsLettersToBeAddedToName

UpdateNameDoesntAllowNonLettersToBeAddedToName

Из этих названий тестовых методов видно, что мы действительно проверяем, выполняется ли «юнит» работы метода UpdateNameWithCharacter. Эти названия тестов могут показаться слишком длинными и подробными, но это нам на пользу.

Каждый написанный вами юнит-тест является частью комплекса тестов. Комплекс тестов содержит все юнит-тесты, относящиеся к логической группе функционала. Если любой тест из комплекта не проходит проверку, то её не проходит весь комплект тестов.


Пишем первый юнит-тест

В качестве первого теста неплохо будет проверить, действительно ли астероиды движутся вниз. Добавим в скрипт TestSuite следующий метод и частную переменную:

Здесь всего несколько строк кода, но они выполняют множество действий:

 


1.     Это атрибут.

2.     Создаём экземпляр Game.

3.     Здесь мы создаём астероид, чтобы можно было следить за тем, двигается ли он.

4.     Отслеживание исходной позиции необходимо для того, чтобы убедиться, что астероид сместился вниз.

5.     Все юнит-тесты Unity являются корутинами, поэтому нужно добавить мягкий возврат. Также мы добавляем шаг времени в 0,1 секунды, чтобы симулировать течение времени, за которое астероид должен был двигаться вниз.

6.     Это этап утверждения (assertion), на котором мы утверждаем, что позиция астероида меньше исходной позиции (то есть он сдвинулся вниз). Понимание утверждений — важная часть юнит-тестирования, и NUnit предоставляет различные методы утверждений. Прохождение или непрохождение теста определяется этой строкой.

7.     Всегда важно подчищать (удалять или сбрасывать) код после юнит-теста, чтобы при запуске следующего юнит-теста не оставалось артефактов, которые могли бы повлиять на этот тест. Нам достаточно просто удалить игровой объект, потому что для каждого теста мы создаём полностью новый экземпляр game.

 

Прохождение тестов


В окне Test Runner раскройте все строки со стрелками. Вы должны увидеть тест AsteroidsMoveDown в списке с серыми кружками:


Серый кружок означает, что тест пока не выполнялся. Если тест был запущен и пройден, то рядом показывается зелёная стрелка. Если тест завершился с ошибкой, то рядом с ним будет отображён красный X. Запустим тест, нажав на кнопку RunAll.


При этом создастся временная сцена и будет запущен тест. После завершения вы должны увидеть, что тест пройден.


Добавление теста в комплект тестов

Следующий тест будет тестировать конец игры, когда корабль сталкивается с астероидом. Открыв в редакторе кода TestSuite, добавьте под первым юнит-тестом показанный ниже тест и сохраните файл:

Мы уже видели бОльшую часть этого кода в предыдущем тесте, но здесь есть некоторые отличия.

Вернитесь в окно Test Runner и вы увидите, что там появился новый юнит-тест.

На этот раз мы запустим вместо всего комплекта тестов только этот. Нажмите на GameOverOccursOnAsteroidCollision, а затем на кнопку Run Selected.

И вот мы прошли ещё один тест.

Вы могли заметить, что в двух наших тестах есть повторяющийся код: там, где создаётся игровой объект Game и где задаётся ссылка на скрипт Game:


Также вы заметите, что повтор есть в уничтожении игрового объекта Game:

При тестировании такое случается очень часто. Когда дело доходит до запуска юнит-тестов, то на самом деле существует два этапа: этап «настройки» (Setup) и этап «разрушения» (Tear Down).

Весь код внутри метода Setup будет выполняться до юнит-теста (в этом комплекте), а весь код внутри метода Tear Down будет выполняться после юнит-теста (в этом комплекте).


Достоинства юнит-тестирования

У юнит-тестирования есть множество важных плюсов, в том числе и такие:

  • Оно даёт уверенность, что метод ведёт себя так, как ожидалось.
  • Служит документацией для новых людей, изучающих кодовую базу
  • Заставляет вас писать код тестируемым образом.
  • Позволяет изолировать и устранять ошибки быстрее.
  • Не позволяет будущим обновлениям добавлять новые баги в старый работающий код (они называются регрессионными ошибками).

Недостатки юнит-тестирования

Однако у вас может и не быть времени или бюджета на юнит-тестирование. Вот его недостатки которые нужно учесть:

  • Написание тестов может занять больше времени, чем сам код.
  • Плохие или неточные тесты создают ложную уверенность.
  • Для правильной реализации нужно больше знаний.
  • Возможно, важные части кодовой базы нельзя будет покрыть тестами.
  • Некоторые фреймворки не позволяют с лёгкостью тестировать частные методы, что может усложнить юнит-тестирование.
  • Если тесты слишком хрупки, то на обслуживание может уйти много времени.
  • UI тестировать сложно.
  • Неопытные разработчики могут тратить зря время на тестирование не тех аспектов.
  • Иногда тестирование элементов с внешними зависимостями или зависимостями времени выполнения может быть очень сложным.

Список литературы

1.     https://github.com/nunit/docs/wiki

2.     https://habr.com/ru/post/456090/