Моки, фейки и заглушки на C++

в 16:22, , рубрики: c++, game development, unity, Unity 3D, unity3d, Блог компании Plarium, код, модульное тестирование, оптимизация, разработка, С++, тестирование

В переводе представлен новый подход к модульному тестированию огромной базы унаследованного кода на C++, плохо реагирующей на тесты.

Моки, фейки и заглушки на C++ - 1

Мы уделяем много внимания тестированию – отчасти чтобы упростить жизнь себе, отчасти чтобы предоставить разработчикам стабильный и надежный движок Unity. Поэтому продолжаем непрерывно оптимизировать этот процесс.

Мы уже писали о высокоуровневом тестировании на C#, но со временем пришли к выводу, что нельзя забывать о более низкоуровневых, быстрых и точных тестах. Проблема в том, что наша кодовая база очень плохо на них реагирует. Тестирование огромной базы унаследованного кода на C++ – задача не из легких. Но нам все-таки удалось её упростить.

Ознакомившись с существующими решениями, мы выяснили, что ни одно из них нам не подходит (мы искали что-то вроде продуктов Typemock, но они работают только под Windows, и поэтому нам не подходят), и поставили перед собой цель решить проблему своими силами. Разумеется, было бессмысленно переписывать весь массив кода только ради тестирования. Нам нужно было решение, совместимое с нашим оформлением кода C++.

Перехват…

Мы поняли, что хорошо было бы иметь возможность перехватывать функции на любом этапе тестирования и делать из них mock-объекты, фейки или заглушки. Нас устраивает, что функция X напрямую вызывает функцию Y при условии, что функцию Y можно будет перехватить и превратить во что угодно.

Тогда мы подумали: нужно пропатчить код! Всё указывало на необходимость замены кода в режиме реального времени для профилирования. Но тут появилась загвоздка: многие платформы не поддерживают возможность изменения кода во время выполнения.

… во время компиляции…

Мы не отчаивались: в конце концов, патчить можно и во время компиляции! Оказалось, что и здесь не всё так просто. Этот процесс уже был успешно реализован, например компанией Bullseye, чьи продукты мы используем для тестирования покрытия кода. Но он всё равно слишком запутан. Мы используем множество компиляторов для разных платформ, а наши сборки и так сложнее, чем хотелось бы, так что от этого варианта тоже пришлось отказаться.

… с помощью макросов

Хорошо, что в C++ всегда есть запасной вариант – шаблоны и макросы. Итак, я устроился поудобнее и написал парочку шаблонов, разбавив их макросами.
Задумка достаточно проста: на основе механизма перехвата функций можно построить целый фреймворк, изменяющий функции в соответствии с целью тестирования.

Шаг первый: перехватчики.

Моки, фейки и заглушки на C++ - 2

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

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

Моки, фейки и заглушки на C++ - 3

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

Моки, фейки и заглушки на C++ - 4

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

Моки, фейки и заглушки на C++ - 5

Вывод

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

Автор: Plarium

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js