Unit test

На сколько оправданно применение юниттестирования в gamedev'е. На первый взгляд тестирование большинства вещей автоматизации не поддается совсем. Скажем еще можно проверить математику или скажем какие-нибудь утилитарные функции. Но как проверить тот же рендер (да и стоит ли овчина выделки) ума не приложу. Может кто-нибудь уже изучал подобные вопросы - поделитесь мнением.

Последняя правка: пн, 29/08/2011 - 22:03
Submitted by Victor on

Комментарии

Не очень оправдано. Т.е. на унит-тесты точно времени и сил не хватит. Из опыта, возможно покрыть core-functionality (математика, файлы, строки, конфиги и т.п.) полностью автоматическими тестами (в "прошлой жизни" их таких около сотни было). Остальное чуть более редкими тестами -- они более крупные куски функциональности тестят, в достаточно изолированных условиях. Рендер в теории можно проверить автоматом, но это геморно очень. На консоли, положим, 100% гарантия что на двух разных девайсах вывод будет совпадать попиксельно (соответственно, можно делать memcmp() frame-,depth-,stencil-,you_name_it-buffer'а), а вот на пц практически наверняка отличия будут. Главная проблема с тестами -- поддерживать их достаточно утомительно. Однако на "нунах эти тесты" есть два мега-аргумента: 1. собирающиеся тесты -- минимальная гарантия что codebase не поломан вусмерть; 2. т.е. функциональность тестируется достаточно изолированно, тесты служат примерами использования того что тестируется (а доки ведь писать всегда лень/некогда, правда).
Submitted by BLK Dragon on

Но core-functionality как раз та часть которая пишется один раз, тестится и затем в нее очень-очень редко вносятся какието изменения (иначе какая ж она core после этого) - а если ее кто и сломает то бага будет видна думаю сразу, поскольку юзают ядро все кому не лень и в разных ситуациях, т.е. для ядра сам код выступает в роли юнитеста по большому счету.

В итоге получается, что то, для чего автоматизировать тестирование легко - редко изменяется, а то что тестировать не мешало бы регулярно - хрен автоматом протестируешь, ту же игровую логику -- связку GUI<->пользователь, например Sad

Что имелось в виду под термином "в прошлой жизни"?

Можно более подробно про изолированные условия? Как их выбирать? Это какието краевые значения параметров, рандомайз или чтото более хитрое?

По поводу мега-аргументов - они конечно весомые и я с ними согласен. Вопрос только стоят ли эти плюсы тех накладных расходов на поддержании тестов.

Вообщем. Я так понял универсального совета тут нету - все зависит от проекта и команды. Основной подход - пишется ядро, потом его на сколько возможно покрывают тестами, а с остальными модулями как повезет.

Да еще вопрос - а что думаете по поводу стресс-тестов? или они еще меньше нужны чем юнит-тесты?

Submitted by Victor on
Но core-functionality как раз та часть которая пишется один раз, тестится и затем в нее очень-очень редко вносятся какието изменения (иначе какая ж она core после этого) - а если ее кто и сломает то бага будет видна думаю сразу, поскольку юзают ядро все кому не лень и в разных ситуациях, т.е. для ядра сам код выступает в роли юнитеста по большому счету. Core очень даже меняется. И если ты сломаешь, например, что-то в матрицах, то оно конечно прочувствуется в самой игре (здоровенном приложении на надцать сотен тысяч строк) и без изолированного теста с разбегу и не сообразишь что именно и где сломалось. А так собрал/запустил один .ехе, увидел что не все тесты прошли и посмотрел/поправил что сломалось. А "весь код в роли унит-теста" это бред, т.к. он ни разу не "унит" -- использует много чего и сразу. Что имелось в виду под термином "в прошлой жизни"? Два проекта назад. Можно более подробно про изолированные условия? Как их выбирать? Это какието краевые значения параметров, рандомайз или чтото более хитрое? Да ничего хитрого. Просто здравый смысл; если тестим физику, не нужно сцену рисовать с бампом на всём, тенями и постеффектом -- иначе глюки ловить будем не только в физике но ещё и в рисовании. Ну и понятно, что если уж мы тестим коллижн боксов об ландшафт, то боксов нужно кидать сотни и во всяких разных ориентациях :) По поводу мега-аргументов - они конечно весомые и я с ними согласен. Вопрос только стоят ли эти плюсы тех накладных расходов на поддержании тестов. Тесты стоит поддерживать хотя бы потому что они одновременно примеры. И потом когда есть пачка приложений использующих "движок" (помимо самой игры/игр), появляется больше разных сочетаний использования всяких фич и соответственно повышается вероятность наткнутся на какие-нить проблемы (которые остались бы незамечеными). Да еще вопрос - а что думаете по поводу стресс-тестов? или они еще меньше нужны чем юнит-тесты? Они нужны так же как и "обычные". Т.е. вот запустить игру на ночь и посмотреть утром, выжил ли АИ надцать сеансов игры, не набежало ли memory-leak'ов на пару гигабайт и т.п. Ну или "а вот что если нарисовать надцать сотен объектов со всеми этими бумпами, FPS ниже плинтуса не упадёт?". На консоли вообще в самом начале стоит стресс-тест набросать -- просто чтоб понять, например, можем ли мы в принципе иметь 20 персов с рэгдоллами на экране; если нет -- то надо game-design менять :)
Submitted by BLK Dragon on

>> Core очень даже меняется.

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

Хотя с другой стороны код игры большей частью будет лежать наверное в скриптах... Интересно юнит-тесты для скриптов пишут вообще?

>> А "весь код в роли унит-теста" это бред, т.к. он ни разу не "унит" -- использует много чего и сразу.

Да... с унит я возможно перегнул Smile

>> Два проекта назад.

А в текущем как? без юнит тестов вообще или наоборот 100%-ое покрытие кода тестами?

>> На консоли вообще в самом начале стоит стресс-тест набросать -- просто чтоб понять, например, можем ли мы в принципе иметь 20 персов с рэгдоллами на экране; если нет -- то надо game-design менять

framerate friendly ai рулит Smile

А чем пользуетесь в качестве платформы для юнит тестов? Гугл в основном отправляет на CppUnit (клон JUnit, насколько понял, только на сях). И когда происходит тестирование? После каждого чекина, во время сборки билда или по запросу девелопера?

Submitted by Victor on
Стоит ли писать тесты под все еще меняющийся код? Не случится ли так что тесты окажутся сдерживающем фактором в развитии кода? Ну так изменение кода сопровождается изменением этих тестов -- смотреть-то где то нужно, что получается в процессе изменений, правда? :) Для скриптов конечно смыла писать тесты нету никакого как по мне. А в текущем как? без юнит тестов вообще или наоборот 100%-ое покрытие кода тестами? Так же. _унит_ тестов не писал вообще. Т.е. Core обычно просто мелкие тесты (но они строго говоря не unit test), всё что выше -- более "крупно и редко" тестится. А чем пользуетесь в качестве платформы для юнит тестов? Для коре была небольшая пачка шаблонов/макросов; со всякими *нитами не морочились (дело не в NIH, человек это всё делавший годами работает с этим барахлом). Тесты проверяются руками, полную автоматику сделать сложно -- просто слишком много усилий нужно, нет возможности.
Submitted by BLK Dragon on

На rsdn'е нашел статью "Mock-объекты с использованием библиотеки cppmock". Вот пару цитат:


Mockpp – платформо-независимая библиотека для создания mock-объектов на С++. Она написана с использованием идеологии, заимствованной из Mock Objects for Javа и EasyMock. Ее задача – облегчить модульное тестирование.

Основная проблема при проведении unit-тестов заключается в трудности воспроизведения окружения, необходимого для теста. Предположим, что вы написали тест для класса, который работает с базой данных и должен определенным образом реагировать на неверную версию БД, например, сгенерировать определенное исключение. Воспроизвести такую ситуацию довольно сложно – надо иметь БД, которая содержит определенный номер версии. Для другого теста вполне может понадобиться еще какая-нибудь конфигурация базы данных, и т.д. К тому же, скорость выполнения подобных тестов оставляет желать лучшего, а для TDD (Test Driven Development) это существенно, т.к. тесты запускаются очень часто. В конечном итоге, сложность создания настоящего окружения для тестов вынудит разработчика отказаться от тестирования.

В качестве решения этой проблемы предлагается концепция Mock-объектов, которая позволяет заменить реальное окружение для тестов на mock-объекты (от англ. mock - подражание, имитирование) с заданным поведением, позволяющим воспроизводить конкретные ситуации, типа той, которая описана выше.

Mock-объекты предоставляют фиктивную реализацию интерфейсов, которые являются окружением для тестируемого кода. Они эмулируют настоящую функциональность и контролируют поведение тестируемого кода. Например, они позволяют ввести ограничения на количество выводов определенной функции, ограничить число вызываемых функций, задать определенное возвращаемое значение в зависимости от переданных параметров. Эти объекты не предназначены для использования в рабочем коде и используются только в тестах.

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

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

Кроме варианта, позволяющего заменять реализацию окружения, используя полиморфизм, есть вариант с использованием шаблонов. Такой вариант подразумевает использование реализации интерфейса как параметра шаблона класса. У каждого из этих методов есть свои преимущества и недостатки.

Недостаток использования указателя на реализацию - потенциально есть вероятность, что указатель не будет инициализирован, кроме того, тратится некоторое время на выделение памяти и на виртуальный вызов, но зато этот способ более нагляден и типобезопасен. Он также позволяет использовать подсказки VisualAssist-а, который достаточно умен, чтобы показывать функции, доступные через оператор “->”.

При использовании шаблонов типобезопасности нет. В данном случае шаблон, по сути, является просто макросом, т.к. туда можно передать любой тип, который реализует набор методов с соответствующими сигнатурами, хотя эту проблему можно решить, используя проверку на наследование на этапе компиляции, реализованную Андреем Александреску. Вторая проблема состоит в отсутствии наглядности – глядя на переменную, которая предоставляет интерфейс, я не могу сказать, какой именно интерфейс она предоставляет. Третья – полное отсутствие подсказок VisualAssist-а. Лично для меня это важно. Smile Опять же, это мое мнение – шаблоны усложняют код. Но, тем не менее, у способа с шаблонами есть одно очень существенное преимущество – он проще. Создавать для каждого класса интерфейс - занятие муторное и вносящее дополнительную сложность в систему. В общем случае стоит выбрать решение с шаблонами.


Звучит заманчиво, но насколько этот весь универсальный полиморфизм отразится на перфомансе или использование темплейтов на читабельности кода? А так же на какие архитектурные жертвы придется пойти. Надо курить тему дальше Smile

И вообще, игра это же не риалтайм приложение и от нее никто не требует управления атомной станцией. На сколько вообще смертельно если игра будет падать скажем раз в сутки, при вызове не часто используемых функций.

Submitted by Victor on
' На сколько вообще смертельно если игра будет падать ' скажем раз в сутки, при вызове не часто используемых

' функций.

Нинасколько. На консоли типовой тест -- 8 часов непрерывной работы. В смысле если оно не сможет работать дольше -- это никого не волнует.

На пц помню Unreal2 падал каждых 15 минут (чудные драйвера Creative) и ничего.

Submitted by BLK Dragon on
http://www.gamasutra.com/features/20050329/roken_pfv.htm

во случайно наткнулся и вспомнил, что говорили про ето

Submitted by Denis on

Денис, спасибо - обязательно прочитаю.

Submitted by Victor on

GameDev.by