JUnit - одна из самых популярных сред модульного тестирования в экосистеме Java. Версия JUnit 5 (также известная как Jupiter) содержит множество интересных нововведений, включая поддержку новых функций в Java 8 и выше. Однако многие разработчики по-прежнему предпочитают использовать среду JUnit 4, поскольку некоторые функции, такие как параллельное выполнение в JUnit 5 все еще находятся в экспериментальной фазе. За исключением нескольких незначительных вещей, JUnit 5 по-прежнему представляет собой важный шаг вперед в эволюции тестовой среды, поскольку он предоставляет расширенные аннотации, которые позволяют тестировать реактивные приложения.  По моему опыту, JUnit 5 - лучшая версия JUnit. Новая структура также включает расширяемую архитектуру и совершенно новую модель расширений, которая упрощает реализацию пользовательских функций. В этом руководстве по JUnit мы подробно рассмотрим расширения JUnit 5 - одну из основных функций платформы JUnit 5. СОДЕРЖАНИЕ Что такого хорошего в JUnit 5? Архитектура JUnit 5 Как зарегистрировать расширения JUnit 5 Условное выполнение теста JUnit 5 с аннотациями Как создать расширения JUnit 5 путем реализации TestInstanceFactory Как протестировать обратные вызовы жизненного цикла в JUnit 5 Постобработка тестового экземпляра в JUnit 5 Обратный вызов перед уничтожением тестового экземпляра в JUnit 5 Разрешение параметра в JUnit 5 Обработка исключений в JUnit 5 Сторонние расширения фреймворка в JUnit 5 Если вы использовали фреймворк JUnit 4, вы согласитесь, что существуют ограниченные (или минимальные) возможности расширения или настройки фреймворка JUnit 4. Это одно из самых узких мест в этой версии фреймворка JUnit. В JUnit 4 такие расширения, как Runners, можно создавать, просто аннотируя тестовый класс с помощью @RunWith (MyRunner.class), чтобы JUnit мог их использовать. Обратной стороной этого подхода является то, что вы используете только один Runner для тестового класса. Это затрудняет составление нескольких бегунов. Однако недостатки, создаваемые Runners с JUnit 4, можно преодолеть с помощью следующих параметров: JUnit 4 использует правила в дополнение к Runners, что предоставляет вам гибкое решение для добавления или переопределения поведения каждого метода тестирования. Можно создавать правила для аннотирования полей тестового класса. Однако у Rules есть проблема постоянства. Проще говоря, правила могут выполняться только до и после запуска теста, но не могут быть реализованы внутри теста. Итак, как среда JUnit 5 решает эту давнюю проблему JUnit 4? JUnit 5 предлагает механизм расширения, который открывает сторонние инструменты или API через модель расширения. Он состоит из единой и последовательной концепции API-интерфейсов расширения для преодоления ограничений конкурирующих точек расширения JUnit 4 (например, Runner, TestRule и MethodRule). Теперь, когда мы рассмотрели суть расширений JUnit 5, вот ряд вопросов, которые возникают у разработчиков Java: Почему мы должны использовать расширения? Сколько усилий требуется для создания расширения JUnit 5? Модель расширения лучше, чем «Модель программирования»? Вот что упоминается в основных принципах JUnit 5: Лучше включить новую функциональность, создав или расширив точку расширения, а не добавляя функциональность как основную. Предыдущие версии фреймворка JUnit (т.е. до JUnit 4) поставлялись в одном jar файле. Однако JUnit 5 архитектурно отличается от более ранних версий JUnit. Поэтому JUnit 5 поставляется в разных модулях, используя новую архитектуру, которая разделяет API, механизм выполнения, выполнение и интеграцию. JUnit 5 может использоваться только с версиями Java выше или равными 8. Вот три модуля, которые составляют архитектуру JUnit 5: Платформа JUnit: предоставляет API для инструментов обнаружения и запуска тестов. Он определяет интерфейс между JUnit и клиентами, которые хотят запускать тесты из IDE, инструментов сборки или консоли. JUnit Jupiter: предоставляет API на основе аннотаций для написания модульных тестов JUnit 5, а также механизм тестирования, который позволяет их запускать. JUnit Vintage: предлагает механизм тестирования для запуска тестов JUnit 3 и JUnit 4, тем самым обеспечивая обратную совместимость (с более ранними версиями платформы JUnit). Цель этой архитектуры - разделить обязанности по тестированию, выполнению и расширению. Это также облегчает интеграцию других тестовых фреймворков с фреймворком JUnit. Если вы QA-инженер, который регулярно пишет тесты, вы обязательно будете использовать модель программирования. С другой стороны, модель расширения предоставляет несколько интерфейсов в виде API-интерфейсов расширений, которые могут быть реализованы поставщиками расширений (разработчиками или поставщиками инструментов) для расширения основных функций JUnit 5. Как видно из архитектуры JUnit 5, показанной выше, модель расширения является частью модуля Jupiter, который позволяет вам расширять основные функции JUnit 5 с помощью гибких и мощных расширений. Кроме того, расширение JUnit 5 преодолевает ограничения расширения JUnit 4, заменяя его механизмы расширения Runners и Rules. Наконец, поскольку JUnit 5 обеспечивает обратную совместимость, вы все равно можете запускать тесты JUnit 4 с JUnit 5 . Модель расширения JUnit Jupiter предоставляется через небольшой интерфейс в пакете org.junit.jupiter.api.extension, который может использоваться разработчиками или поставщиками расширений. Теперь, когда мы рассмотрели основы расширений JUnit 5, давайте напишем код примера, который иллюстрирует расширения JUnit 5. Для этого давайте создадим Java-проект с тремя примерами тестов для Java-класса, используя Eclipse IDE: Если вы работаете в других Java IDE (не Eclipse), вы можете ознакомиться с подробным блог постом, в котором подробно рассказывается, как запустить JUnit из Eclipse IDE . После добавления библиотеки JUnit 5 в путь сборки (или добавления зависимостей для проекта Maven) мы видим, что расширение JUnit 5 находится в org.junit.jupiter.api в пакете org.junit.jupiter.api.extension как показано ниже: Вот пример Java кода, демонстрирующий простое расширение JUnit 5: Как видно из приведенного выше кода, мы использовали аннотации JUnit, связанные с жизненным циклом выполнения теста, которые мы обсудим позже. Регистрация одного или нескольких расширений в JUnit 5 выполняется через механизм Java ServiceLoader. Существует три способа регистрации расширений: декларативно, программно и автоматически. Регистрация одного или нескольких расширений может быть выполнена с помощью аннотаций в тестовом интерфейсе, тестовом классе (или его поле) или тестовом методе в зависимости от типа регистрации: Декларативная регистрация: аннотацию @ExtendWith (classReference.class) следует использовать для применения расширения к полям класса, тестовым интерфейсам, тестовым методам или пользовательским составным аннотациям. Для демонстрирации расширения JUnit 5, мы использовали пример, который показывает обработку исключений результатов теста: Мы использовали аннотацию @ExtendWith (AdditionalOutputExtension.class) для регистрации указанного выше класса, чтобы среда JUnit могла использовать его на более позднем этапе. Программная регистрация: мы можем использовать аннотацию @RegisterExtension, применив ее к полям в тестовых классах: Автоматическая регистрация: мы можем использовать java.util.ServiceLoader для автоматического обнаружения и регистрации сторонних расширений. Во-первых, условное выполнение теста позволяет запускать (включать) или пропускать (отключать) тестовые сценарии в зависимости от определенных условий использу\ API org.junit.jupiter.api.condition. Давайте посмотрим, как аннотации пакета условий можно использовать для реализации условного выполнения теста в JUnit 5. 1. Условия операционной системы Условия операционной системы можно использовать с аннотациями @EnabledOnOs и @DisabledOnOs. Условия помогают запустить тест JUnit 5 на конкретной платформе (или операционной системе). 2. Условия среды выполнения Java Тестовые сценарии можно запускать при определенных условиях, связанных с JRE (Java Runtime Environment), или в определенном диапазоне диапазона версии JRE с использованием аннотаций @EnabledOnJre, @DisabledOnJre и @EnabledForJreRange. 3. Условия собственности системы Тестовые сценарии могут быть включены или отключены в зависимости от системного свойства с помощью аннотаций @EnabledIfSystemProperty и / или @DisabledIfSystemProperty. 4. Условия переменных окружающей среды Тестовые сценарии JUnit 5 могут быть включены или отключены в зависимости от состояния (или значения) переменных среды. Это можно сделать с помощью аннотаций @EnabledIfEnvironmentVariable и @DisabledIfEnvironmentVariable в среде JUnit 5. 5. Пользовательские условия Пользовательские условия могут быть установлены для включения или отключения тестовых сценарии через API расширения ExecutionCondition. Вот два способа реализации тестовых примеров, которые выполняются в определенных (настраиваемых) условиях: Комбинация встроенных аннотаций для создания настраиваемой аннотации, которую можно будет использовать позже в качестве условия тестирования. Комбинированные встроенные аннотации внутри тестового условия могут использоваться как аннотации внутри тестового класса. Это поможет определить условия, при которых следует проводить тест. Пользовательские аннотации также могут быть созданы с нуля с помощью API расширения ExecutionCondition. Используя этот подход, вы можете обойтись без использования встроенных аннотаций. Чтобы продемонстрировать пользовательские аннотации с использованием примера расширения JUnit 5, мы запускаем тесты в условиях среды выполнения (т. е. среда может быть для разработки, контроля качества или производственная), как показано ниже: Здесь условие для запуска теста add() выполняется в тестовой среде или среде разработки (не в реальном времени). Вот как вы можете создать аннотацию @Environment с нуля и реализовать ее в примере расширения JUnit 5: Мы создаем файл Environment.java и устанавливаем атрибут enabledFor, чтобы добавить в него параметры. Затем созданная аннотация должна зарегистрировать расширение условия через файл EnvironmentExecutionCondition с помощью аннотации @ExtendWith. Создайте файл EnvironmentExecutionCondition, в котором будут указаны все условия для реализации ExecutionCondition API. При запуске тестов в среде Dev или QA, тест «add» будет активен и выполнен, тогда как тесты не будут выполняться, если вы находитесь в среде Prod. Чтобы выполнить тесты в данной среде, запустите соответствующую команду для аргументов виртуальной машины в параметре «run configurations»: Среда разработки: -ea -Denvironment = Dev Среда обеспечения качества: -ea -Denvironment = QA Среда Prod (или Live): -ea -Denvironment = live Прочтите: Как запустить тесты Junit из командной строки Мы можем создавать расширения JUnit 5, реализуя API TestInstanceFactory для создания экземпляров тестовых классов. Они должны выполняться перед выполнением каждого метода тестирования. Затем созданный тестовый экземпляр можно получить из инфраструктуры внедрения зависимостей или путем вызова статического фабричного метода для его создания. Следующий пример расширения JUnit 5 демонстрирует использование фабрик тестовых экземпляров во внешних и внутренних классах: Обратные вызовы жизненного цикла - это функции, которые автоматически выполняются до или после определенных методов модели. Например, вы можете использовать обратные вызовы жизненного цикла для автоматического вычисления значения атрибута «full name» перед созданием или обновлением записи пользователя. В жизненном цикле основного тестового экземпляра JUnit 5 определяет жизненный цикл класса и метода, управляемый следующими аннотациями: @BeforeAll @BeforeEach @AfterEach @AfterAll Методы, помеченные @BefсегоoreAll и @AfterAll, должны выполняться до и после всех тестовых методов в классе. С другой стороны, методы, аннотированные @BeforeEach и @AfterEach, должны выполняться соответственно до и после каждого метода тестирования. JUnit создает новый экземпляр для тестового класса перед запуском каждого теста в жизненном цикле тестового экземпляра. Такое поведение направлено на запуск каждого теста отдельно и, таким образом, позволяет избежать побочных эффектов от запуска других тестов. Выполнение этого кода дает следующий результат: Исходя из результата выполнения теста, поведение по умолчанию - следующее: Поведение жизненного цикла теста можно изменить с помощью API org.junit.jupiter.api.TestInstance, который позволяет изменить жизненный цикл по умолчанию (для тестового класса или метода тестирования). Это можно сделать, добавив в тестовый класс аннотацию @TestInstance (TestInstance.Lifecycle.PER_CLASS). Вот обновленный результат выполнения после модификации поведения по умолчанию (жизненного цикла теста): По результату выполнения теста измененное поведение следующее: Помимо жизненного цикла для каждого класса и для каждого метода, JUnit 5 Jupiter предлагает различные интерфейсы, которые определяют API-интерфейсы для расширения тестов в различных точках жизненного цикла выполнения. Поэтому JUnit 5 вызывает обратные вызовы расширений для реализации требуемого поведения. API-интерфейсы являются частью пакета org.junit.jupiter.api.extension. Вот API, определяющие жизненный цикл расширения: AfterAllCallback AfterEachCallback BeforeAllCallback BeforeEachCallback Мы можем создать расширение для тестового класса, реализовав интерфейсы BeforeAllCallback, AfterAllCallback, BeforeEachCallback и AfterEachCallback. Вот как применить указанную точку расширения к тест-классу: Вот результат выполнения: Модель расширений Juniper обеспечивает возможность постобработки тестовых экземпляров после создания тестовых экземпляров путем реализации интерфейса TestInstancePostProcessor. В соответствии с фабрикой тестового экземпляра он может вызывать метод инициализации в тестовом экземпляре, используя, например, зависимости внедрения в экземпляр для использования постобработки тестового экземпляра. Чтобы проиллюстрировать это, мы возьмем пример системы журналирования из API-интерфейса log4j, который выполняет и записывает журналы после каждого выполнения теста. Давайте рассмотрим пример исключения JUnit 5: Модель расширений также определяет API для расширений, которые необходимо обработать между тестовыми экземплярами и их окончательным уничтожением. Например, обратный вызов перед уничтожением тестового экземпляра обычно используется в таких случаях, как очистка внедренных зависимостей после их использования в тестовом экземпляре. Большинство методов тестирования не имеют параметров. Мы используем интерфейс ParameterResolver при использовании параметров, который определяет API org.junit.jupiter.api.extension.ParameterResolver для расширений. Он предоставляет функциональные возможности для динамического разрешения параметров во время выполнения. Следующие конструкторы и аннотированные методы тестового класса могут иметь один или несколько параметров: @Test @TestFactory @BeforeEach @AfterEach @BeforeAll @AfterAll Разрешение параметра может быть выполнено с помощью имени, типа, аннотации или их комбинации. JUnit 5 реализует внедрение зависимостей с использованием параметров для конструкторов и методов тестовых классов, чтобы сделать это возможным. Эти параметры должны быть разрешены во время выполнения экземпляром типа ParameterResolver, который необходимо зарегистрировать ранее. По умолчанию JUnit 5 автоматически регистрирует ParameterResolver, используя три встроенных преобразователя: TestInfoParameterResolver: используется для разрешения, внедрения экземпляра типа TestInfo и получения информации о тесте, который выполняется. RepetitionInfoParameterResolver: используется для внедрения экземпляра типа RepetitionInfo только для повторных тестов. TestReporterParameterResolver: используется для внедрения экземпляра типа TestReporter, позволяя ему добавлять полезную информацию в отчет о тестировании. Если вы используете JUnit 4, вы можете ознакомиться с блогом, в котором подробно рассказывается о параметризации в JUnit для Selenium Automation. Интерфейс TestExecutionExceptionHandler определяет API, реализующий расширения, позволяющие полностью настроить поведение тестового примера при возникновении исключения. В продолжение предыдущего примера расширения JUnit 5 мы использовали ArithmeticException для создания тестового класса в тестовом сценарии для divide, как показано ниже: Он расширен до класса обработчика исключений для обработки исключения, вызванного операцией деления (при обработке деления на ноль): Можно использовать традиционный метод создания исключения (с помощью try… catch, Rules и т. д.) или через аннотации, реализовав интерфейс TestExecutionExceptionHandler. Читать дополнительно: Mastering Selenium Testing With JUnit Asserts Принцип JUnit - предоставить легко расширяемую базовую структуру, которая позволяет пользователям работать быстрее, чем разработчики API. Эта функция позволяет создавать API-интерфейсы, которые служат основой для сторонних библиотек. Хотя JUnit 5 включает ряд сторонних расширений, мы рассмотрим следующие расширения, широко используемые сообществом разработчиков: MockitoExtension Selenium-Jupiter Spring TestContext: SpringExtension for Jupiter JUnit 5 лучше всего подходит для запуска модульных тестов. Однако при выполнении интеграционного тестирования между модулями (или взаимозависимыми ресурсами) и проверки взаимодействия заглушки или макеты используются для имитации (или представления) зависимых или недоступных ресурсов. Mockito - это фреймворк, который позволяет создавать фиктивные объекты для интеграционного тестирования. Вот основные способы использования MockitoExtension: Ручной подход Использование аннотаций Использование расширений JUnit 5, доступных в артефакте mockito-junit-jupiter (наиболее предпочтительный вариант) Использование расширения Mockito можно увидеть в действии, используя расширение и добавив @ExtendWith в тестовый класс и аннотируя моделируемые поля с помощью @Mock. Например, если нам нужно протестировать класс SERVICE и имитировать базу данных, нам нужно использовать следующий код: Тестовый класс будет выглядеть так: Объединив силу Selenium, самой популярной среды тестирования веб-браузеров, и мощность JUnit 5, selenium-jupiter позволяет создавать тесты Selenium с использованием локальных и/или удаленных браузеров. Благодаря этому вы можете запускать различные типы тестов для проверки функциональности веб-приложений и мобильных приложений. Кроме того, расширение selenium-jupiter может использоваться для автоматизации Selenium тестирования. Выполните автоматизацию Selenium тестирования в облаке с помощью JUnit Framework. Для проектов Maven следует использовать следующую зависимость: Selenium-Jupiter можно использовать, просто используя аннотацию @ExtendWith в интерфейсе SeleniumJupiter для выполнения тестирования кроссбраузерной совместимости. Вот демонстрационный пример: Читать далее: Automated Testing With JUnit And Selenium For Browser Compatibility Как использовать Selenium-Jupiter для автоматизации Selenium тестирования  Selenium-Jupiter поддерживает тестирование удаленных веб-браузеров в Selenium Grid с помощью комбинации DriverCapabilities и RemoteWebDriver. Вы также можете выполнить параллельное тестирование в Selenium, запустив тесты в различных комбинациях браузера и платформы с помощью LambdaTest. Как использовать Selenium-Jupiter для тестирования мобильных устройств Чтобы создать экземпляр ApiumDriver для управления мобильными устройствами, аннотация DriverCapabilities. Selenium-Jupiter автоматически запустит экземпляр сервера Appium. Как использовать Selenium-Jupiter для выполнения  автоматизации Selenium тестирования  в Cloud Grid Selenium-Jupiter позволяет запускать автоматизации Selenium тестов на облачной платформе кроссбраузерного тестирования, такой как LambdaTest. Основными преимуществами облачного тестирования являются улучшенное покрытие браузера, устранение связанных с окружающей средой задержек в расписании, повышение качества продукта и снижение совокупной стоимости владения (TCO). Ознакомьтесь с нашим руководством по облачному тестированию, в котором описаны многочисленные преимущества переноса тестов в облачную среду Selenium Grid, такую ​​как LambdaTest. После создания учетной записи на LamdaTest обратите внимание на имя пользователя и доступ из раздела профиля LambdaTest. Эти учетные данные необходимы для доступа к облачной сетке. Затем вы можете сгенерировать желаемые возможности с помощью LambdaTest Capabilities Generator. Ниже показан пример запуска теста JUnit 5 в LambdaTest Grid: Вот снимок во время выполнения, который указывает, что выполнение теста было успешным. Spring TestContext, представленный в Spring 5, представляет собой среду Spring, которая предлагает полную интеграцию с моделью программирования JUnit 5 Jupiter. Его можно найти в пакете org.springframework.test.context.junit.jupiter.SpringExtension. Его можно использовать, просто аннотируя тестовый класс JUnit Jupiter любой из следующих аннотаций: @ExtendWith(SpringExtension.class) @SpringJunitConfig(TestConfig.class) @SpringJUnitWebConfig(TestConfig.class) Ниже показан пример расширения JUnit 5, демонстрирующий использование Spring TestContext: Модель расширения JUnit 5, встроенная в Jupiter, решила внутренние проблемы в точках расширения JUnit 4. Модель реализует несколько встроенных точек расширения и обеспечивает их настройку и групповое использование. Это позволяет разработчикам расширений реализовывать интерфейсы для включения дополнительных возможностей для JUnit 5. Расширения JUnit 5 позволяют улучшать и расширять возможности JUnit. Однако в некоторых фреймворках также есть полностью интегрированные и адаптированные точки расширения JUnit, позволяющие их повторно использовать, что делает модель расширения Jupiter более мощной и упрощает тесты в соответствии со средой и требованиями приложения. Поэтому настоятельно рекомендуется использовать точки расширения, интегрированные или настраиваемые, чтобы сделать тесты более надежными. В этой статье не представлены полностью все точки расширения, интегрированные с JUnit 5, или даже все расширения сторонних библиотек. Поэтому, если вас интересует точка расширения или сторонняя платформа расширений, которая не показана здесь, вы можете сообщить нам, чтобы заполнить это руководство в соответствии с интересами читателей. Мы также можем более подробно проработать те, которые не кажутся вам понятными в этом руководстве. Нам также интересны ваши отзывы об использовании точек расширения JUnit Jupiter в ваших проектах. Исходный код приведенных выше примеров можно найти на GitHub.