JEP 281: HotSpot C++ Unit-Test Framework
Фреймворк модульного тестирования на C++ для HotSpot
| Автор | Stefan Sarne |
| Ответственный | Igor Ignatyev |
| Тип | Feature |
| Область | Implementation |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Компонент | hotspot / test |
| Обсуждение | hostspot dash dev at openjdk dot java dot net |
| Трудоёмкость | M |
| Длительность | M |
| Рецензенты | Aleksandre Iline, Mikael Vidstedt |
| Одобрен | Mikael Vidstedt |
| Создан | 2014/06/24 11:35 |
| Обновлён | 2025/02/05 11:18 |
| Задача | 8047975 |
Аннотация
Сделать возможной и поощрять разработку модульных тестов на C++ для HotSpot.
Цели
-
Поддержка написания и выполнения модульных тестов для методов, классов и подсистем
-
Поддержка модульных тестов, в которых тестируется только один модуль и больше ничего не запускается
-
Поддержка тестов, которым требуется инициализация VM
-
Поддержка быстрых тестов со временем выполнения порядка миллисекунд
-
Поддержка как позитивного, так и негативного тестирования
-
Возможность изоляции тестов
-
Поддержка тестов, расположенных рядом с исходным кодом продукта
-
Поддержка интеграции с текущей инфраструктурой
-
Отдельный результат для каждого теста
-
Возможность легко запустить отдельный тест (из командной строки)
-
Возможность предоставить минимальные воспроизводящие примеры для падений тестов
-
Поддержка IDE
-
Возможность развивать фреймворк, в том числе быстро вносить в него исправления
-
Поддержка выбора и группировки тестов с детализацией, аналогичной
jtreg -
Возможность тестировать любую цель компиляции, как product, так и debug
-
Возможность тестировать платформенно-зависимый код
-
Минимальная документация: вики с инструкциями и примеры в репозитории
-
Возможность исключать тесты из выполнения путём изменения исходного кода тестов или других файлов, например списков исключений
-
Поддержка преобразования всех внутренних тестов
-
Поддержка платформ сборки JDK 9, поддерживаемых Oracle
Что не является целью
- Заменить тесты на Java. Модульное тестирование на C++ дополняет тестирование для других сценариев использования.
Мотивация
В хорошо протестированную кодовую базу проще вносить изменения. Набор тестов помогает инженеру, который вносит изменения, проверяя, что ничего неожиданно не сломалось.
Сегодня в HotSpot много тестов, но немного тестов самого прямого типа, и писать такие тесты недостаточно просто.
Внедрение фреймворка тестирования для C++ — первый шаг к улучшению набора тестов. Фреймворк тестирования для C++ позволяет писать тесты на том же языке, что и JVM, и тогда внутренние структуры напрямую доступны тестовому коду. По сравнению с функциональным тестированием из Java с помощью jtreg это открывает новые возможности легко писать небольшие точные тесты.
Возможность разрабатывать модульные тесты для существующей функциональности позволит изолированно тестировать код на C++ для новых возможностей и упростит написание регрессионных тестов для некоторых наиболее экзотических проблем.
Описание
Фреймворк Google Test (GTest) — это фреймворк модульного тестирования для C++, который лучше всего соответствует нашим целям. Это фреймворк семейства xUnit, широко распространённый в сообществе. Фреймворк GTest:
- Разрабатывается и поддерживается другими
- Интегрируется с Eclipse IDE
- Имеет проверенный в бою, полный API
- Имеет богатую возможностями модель выполнения
- Имеет готовую документацию и примеры
- Поддерживает результаты тестов в стиле JUnit и интеграцию с Hudson и Jenkins
Чтобы писать тесты для HotSpot с помощью GTest, нужно выполнить несколько задач, и ещё несколько задач нужны, чтобы его улучшить. В текущем состоянии GTest:
- Используются конструкции C++, которые HotSpot не использует и которые в HotSpot отключены, например исключения, шаблоны и STL
- Solaris/Oracle Solaris Studio не входит в число поддерживаемых ОС/компиляторов
Следует признать, что GTest — сторонний инструмент, а значит, он добавляет ещё одну зависимость к существующему процессу сборки и тестирования. Кроме того, GTest довольно большой (71K строк кода) и в будущем может измениться несовместимым образом. Чтобы изменения в самом фреймворке тестирования не приводили к проблемам, нам нужно контролировать, какая версия GTest используется, и иметь возможность указывать её в рамках сборки (хотя её должно быть можно переопределить). Было бы полезно иметь систему зависимостей, которая автоматически загружает и устанавливает нужную версию GTest.
Структура каталогов тестов HotSpot
Новым тестам нужно место в дереве исходного кода. Корневой каталог тестов должен находиться рядом с исходным кодом продукта, но не внутри него, примерно как в существующей структуре каталогов тестов. Для ясности тесты не следует смешивать с существующими тестами jtreg: их нужно разделить на два каталога. Мы предлагаем разделить текущий каталог jdk9/hotspot/test на два подкаталога:
jdk9/hotspot/test/javajdk9/hotspot/test/native
Существующие тесты jtreg переместятся ниже, в каталог java (включая код JNI и shell-скрипты). Файл TEST.ROOT останется на верхнем уровне.
Цели сборки и двоичные файлы
Тестовый код никак не должен заметно влиять на двоичные файлы продукта. Например, не должно экспортироваться дополнительных символов, а пакеты продукта не должны содержать тестов. Скомпилированные тесты будут помещены в отдельные тестовые пакеты, по одному на конфигурацию. Тесты будут компоноваться с символами, экспортируемыми из неурезанной (non-stripped) библиотеки JVM, которая создаётся из тех же объектных файлов, что и обычная библиотека.
Запуск тестов
Тесты должно быть легко запускать из командной строки с помощью make. Чтобы результаты тестов были совместимы с результатами других тестов, запуск, возможно, будет выполняться через тестовую обёртку jtreg, которая, в свою очередь, вызывает GTest. GTest сам умеет выдавать результаты в стиле JUnit, которые хорошо интегрируются с Hudson/Jenkins и подобными инструментами.
Альтернативы
Альтернатива 1: HUTT. Ранее был создан прототип фреймворка под названием «HotSpot Unit Test Tool» (HUTT); это фреймворк семейства xUnit. Он значительно меньше, чем GTest (2K строк кода), и не является внешней зависимостью. Это жизнеспособное, но более дорогое решение. Кроме того, у него нет поддержки IDE.
Альтернатива 2: продолжать писать тесты на Java. К внутреннему устройству JVM можно получить доступ через Whitebox API. По сравнению с этим добавлять Whitebox API трудоёмко, и такие тесты медленно выполняются. Этот подход подходит для некоторых видов интроспекции, но далеко не для всего тестирования. Тесты на Java дороже писать и выполнять, поскольку для получения качественных тестов, нацеленных на конкретную функциональность, тесты становятся очень сложными, и часто трудно гарантировать детерминированность.
Альтернатива 3: продолжать использовать внутренние тесты. Такое решение не достигло бы многих из заявленных целей.
Риски и допущения
Риск: GTest может развиваться в направлении, в котором он станет непригодным как фреймворк модульного тестирования для HotSpot. Этот риск оценивается как низкий.
План снижения риска: сделать форк фреймворка GTest или использовать HUTT.
Риск: бэкпортирование исправлений GTest окажется очень дорогим.
План снижения риска: сделать форк фреймворка GTest или использовать HUTT.