Спустя восемь лет после JUnit 5 выходит новая версия популярного фреймворка. JUnit 6 — это не просто обновление, а переход к современной экосистеме Java и Kotlin. В новом переводе от команды Spring АйО узнаем, что новая версия требует Java 17+, унифицирует версии компонентов, удаляет deprecated API и внедряет поддержку JSpecify для строгого null-safety.

JUnit 6 вышел спустя восемь лет после релиза JUnit 5. Это не просто очередное обновление — это значительный шаг вперёд в направлении модернизации.

Рассмотрим основные улучшения, и изменения, ломающие обратную совместимость.

JUnit 6 требует Java 17+ (и Kotlin 2.2+)

JUnit 6 повышает минимальную требуемую версию Java с 8 до 17. Это изменение обусловлено двумя ключевымифакторами:

  1. Развитие Java: с момента выхода версии 8 было внедрено множество улучшений.

  2. Переход экосистемы на Java 17.

Например:

Для проектов, которые всё ещё используют версии Java до 17, JUnit 5 будет поддерживаться как минимум ещё в течение одного года.

Для пользователей Kotlin JUnit 6 теперь требует версию Kotlin 2.2 или новее.

JUnit Platform, Jupiter и Vintage теперь имеют единую версию

Фреймворк JUnit состоит из трёх основных архитектурных компонентов:

  • Platform — предоставляет API движка для запуска тестов.

  • Jupiter — предоставляет API для написания тестов.

  • Vintage — реализует движок, позволяющий запускать тесты, написанные с использованием JUnit 3 и 4.

Однако в JUnit 5 только артефакты Jupiter и Vintage выпускались под одной и той же версией, тогда как артефакты Platform использовали отдельную схему версионирования.

Например:

junit-jupiter-engine:5.13.3  
junit-vintage-engine:5.13.3  
junit-platform-engine:1.13.3  

Как видно, версия junit-platform-engine отличается от остальных.

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

В результате после миграции на JUnit 6 можно использовать единую версию:

junit-jupiter-engine:6.0.0  
junit-vintage-engine:6.0.0  
junit-platform-engine:6.0.0 

Различные улучшения и устаревшие API

JUnit 6 представляет собой значительную переработку кодовой базы за счёт удаления deprecated API и кода, а также внедрения ряда улучшений.

Новые функции и улучшения API:

  • Модификатор suspend в Kotlin теперь может применяться к методам тестов и жизненного цикла.
    Комментарий от эксперта Spring АйО Михаила Поливахи:
    Для тех, кому любопытно, в движке Junit вызов @Test метода, который помечен модификатором suspend, реализован через простой runBlocking вызов.

    https://github.com/junit-team/junit-framework/pull/4530/files#diff-be2eb6e242e221ae7e4bc2ee1c53de6f0cb987ae91bbc30953cbd43ff1b4e852R55

  • Названия для @ParameterizedClass и @ParameterizedTest теперь оформляются в едином стиле: пары «имя = значение» отображаются с пробелами — например, fruit = apple вместо fruit=apple.

  • Для согласованности с методами тестов, классы @Nested, объявленные в одном и том же внешнем классе или интерфейсе, теперь упорядочиваются детерминированным, но намеренно неочевидным способом.

Устаревшие и удалённые элементы публичного API:

  • Значения enum JRE от JAVA_8 до JAVA_16 объявлены deprecated, так как они больше не поддерживаются в runtime — новая базовая версия Java теперь JAVA_17.

  • Аннотации @EnabledForJreRange и @DisabledForJreRange теперь по умолчанию используют JAVA_17 в качестве минимального значения.

  • Класс MethodOrderer.Alphanumeric удалён.

  • Метод ReflectionSupport.loadClass(String) удалён.

  • Метод ReflectionUtils.readFieldValue(…) удалён.

  • Метод ReflectionUtils.getMethod(…) удалён.

  • Метод InvocationInterceptor.interceptDynamicTest(Invocation, ExtensionContext) удалён.

  • Движок JUnit Vintage теперь помечен как deprecated и будет фиксировать проблему на уровне INFO при обнаружении хотя бы одного тестового класса JUnit 4.

Удаление модулей и интеграции

  • Модули junit-platform-runner и junit-platform-jfr были удалены. Функциональность JFR теперь интегрирована в модуль junit-platform-launcher.

  • Модуль junit-platform-suite-commons теперь включён в состав junit-platform-suite.

  • Артефакт junit-jupiter-migrationsupport и содержащиеся в нём классы объявлены как deprecated и будут удалены в следующей мажорной версии.

Совместимость со сборочными инструментами:

Поддержка Maven Surefire/Failsafe версий ниже 3.0.0 прекращена.

Полный список изменений доступен в официальных release notes.

Более стабильный и производительный парсинг CSV для @CsvSource и @CsvFileSource

JUnit 6 перешёл с библиотеки univocity-parsers, которая больше не поддерживается, на FastCSV для обработки CSV-данных.

Это обеспечивает:

Хотя общее поведение остаётся в значительной степени совместимым с JUnit 5, есть несколько изменений, которые могут потребовать адаптации тестов или входных файлов:

  • Атрибут lineSeparator в @CsvFileSource удалён. Разделитель строк теперь определяется автоматически — допускаются любые из \r, \n или \r\n.

  • Лишние символы после закрывающей кавычки больше не допускаются в @CsvSource и @CsvFileSource. Например, если используется одинарная кавычка как символ кавычек, то значение CSV 'foo’INVALID,'bar' теперь вызовет исключение. Это предотвращает тихую обработку некорректного ввода.

  • Атрибуты вроде ignoreLeadingAndTrailingWhitespace, nullValues и другие в @CsvSource и @CsvFileSource теперь применяются не только к обычным значениям, но и к заголовкам.

  • Тексты исключений и причины ошибок при обработке некорректного CSV-ввода могут отличаться от прежних.

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

JUnit 6 улучшает работу с null-safety благодаря аннотациям JSpecify

В JUnit 5 информация о null-safety передавалась неформально через JavaDoc — это было полезно для разработчиков, но недоступно для инструментов. В результате возникали типичные проблемы:

  • NullPointerException в runtime.

  • Дополнительные преобразования типов или проверки на null в Kotlin из-за различий между nullable и non-nullable типами.

JUnit 6 решает эти проблемы с помощью поддержки аннотаций JSpecify. Эти аннотации:

Начиная с JUnit 6, все публичные API последовательно указывают информацию о null-safety с помощью аннотации @Nullable.

Например, метод Arguments.of() теперь явно показывает, что принимает аргументы, которые могут быть равны null, но всегда возвращает ненулевое значение:

static Arguments of(@Nullable Object... arguments) {
  return of(arguments);
}

Типы без аннотаций по умолчанию считаются non-nullable.

Заключение

JUnit 6 представляет собой значительный этап в развитии фреймворка. Хотя это не полная переработка, как в случае с JUnit 5, новая версия предлагает ряд существенных улучшений за счёт:

  • использования современных возможностей языка Java;

  • внедрения полноценной null-safety с помощью JSpecify;

  • упрощения управления зависимостями.


Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.

Комментарии (0)