openjdk.ruOpenJDK на русском

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/java
  • jdk9/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.