В комментарии к нему @LeshaRB задал вопрос: «Это будет перевод всех статей цикла Junit5 или просто одна?»
В этом туториале по JUnit 5 рассказывается о том, как JUnit адаптировал стиль кодирования Java 8 и некоторые другие функции. Узнайте, чем JUnit 5 отличается от JUnit 4.
JUnit 5 — наиболее широко используемая среда тестирования для приложений Java. JUnit долгое время отлично справлялся со своей задачей.
Между тем, JDK 8 привнес в java интересные функции и, в первую очередь, лямбда-выражения. JUnit 5 был нацелен на адаптацию стиля программирования Java 8; вот почему Java 8 является минимально необходимой версией для создания и выполнения тестов в JUnit 5 (хотя можно запускать тесты, написанные с помощью JUnit 3 или JUnit 4 для обратной совместимости).
Оглавление
Архитектура JUnit 5
Написание наборов тестов
Обратная совместимость для JUnit 4
1. Архитектура JUnit 5
По сравнению с JUnit 4, JUnit 5 состоит из нескольких разных модулей из трех разных подпроектов:
JUnit 5 = Платформа JUnit + JUnit Jupiter + JUnit Vintage
JUnit Jupiter: включает новые модели программирования и расширения для написания тестов. В нем есть все новые аннотации junit и TestEngine реализация для запуска тестов, написанных с этими аннотациями.
Платформа JUnit: чтобы иметь возможность запускать тесты junit, IDE, инструменты сборки или плагины должны включать и расширять API платформы. Он определяет TestEngine API для разработки новых фреймворков тестирования, работающих на платформе. Он также предоставляет средство запуска консоли для запуска платформы из командной строки и создания подключаемых модулей для Gradle и Maven.
Архитектура JUnit 5
2. Установка
Вы можете использовать JUnit 5 в своем проекте Maven или Gradle, включив как минимум следующие зависимости:
junit-jupiter-api: это основной модуль, в котором расположены все основные аннотации, такие как @Test, аннотации и утверждения метода жизненного цикла.
junit-jupiter-engine: он имеет реализацию тестового движка, которая требуется во время выполнения для выполнения тестов.
junit-platform-suite: поддержка @Suite, предоставляемая этим модулем, чтобы сделать средство запуска JUnitPlatform устаревшим.
pom.xml
build.gradle

3. Аннотации JUnit 5
JUnit 5 предлагает следующие аннотации для написания тестов.
Аннотации
Описание
Аннотированный метод будет запускаться перед каждым тестовым методом в тестовом классе.
Аннотированный метод будет запускаться после каждого тестового метода в тестовом классе.
Аннотированный метод будет запущен перед всеми тестовыми методами в тестовом классе. Этот метод должен быть статическим.
Аннотированный метод будет запущен после всех тестовых методов в тестовом классе. Этот метод должен быть статическим.
Он используется, чтобы пометить метод как тест junit.
Используется для предоставления любого настраиваемого отображаемого имени для тестового класса или тестового метода
Он используется для отключения или игнорирования тестового класса или тестового метода из набора тестов.
Используется для создания вложенных тестовых классов
Пометьте методы тестирования или классы тестов тегами для обнаружения и фильтрации тестов.
4. Написание тестов
Между JUnit 4 и JUnit 5 нет больших различий в стилях написания тестов. Вот образцы тестов с их методами жизненного цикла.
Обратите внимание, что все аннотации взяты из пакета org.junit.jupiter.api.
JUnit 5 Tests
5. Написание наборов тестов
Используя наборы тестов JUnit 5, вы можете запускать тесты, распределенные по нескольким тестовым классам и различным пакетам. JUnit 5 предоставляет эти аннотации для создания наборов тестов.
Для выполнения пакета вам необходимо использовать @Suite аннотацию и включить модуль junit-platform-suite в зависимости проекта.
6. Assertions
Assertions (утверждения) позволяют сравнить ожидаемый результат с фактическим результатом теста.
7. Assumptions
Класс Assumptions (предположения) предоставляет static методы для поддержки выполнения условного теста на основе предположений. Неуспешное предположение приводит к прерыванию теста.
Предположения обычно используются всякий раз, когда нет смысла продолжать выполнение данного метода тестирования. В отчете о тестировании эти тесты будут отмечены как пройденные.
8. Обратная совместимость с JUnit 4
JUnit 4 существует уже довольно давно, и на junit 4 написано множество тестов. JUnit Jupiter также должен поддерживать эти тесты. Для этого был разработан подпроект JUnit Vintage.
JUnit Vintage предоставляет TestEngine реализацию для запуска тестов на основе JUnit 3 и JUnit 4 на платформе JUnit 5.
9. Заключение
JUnit 5 кажется таким захватывающим и многофункциональным. И теперь он открыт для расширения сторонними инструментами и API. Как автор тестов, вы можете не чувствовать очень большой разницы, но, когда вы используете расширение или попытаетесь разработать плагин для IDE, вы его оцените.
Вы также можете рассмотреть возможность добавления тестовых шаблонов в Eclipse IDE, чтобы повысить скорость разработки как разработчика.
Пишем JUnit тесты на Java
После написания программы хороший программист покрывает свой код тестами, дабы убедиться, что методы работают так, как он планировал.
Тесты бывают нескольких видов:
Сегодня нас интересуют юнит тесты. Де-факто фреймворком для написания юнит тестов на языке Java является JUnit.
Я сейчас не буду расписывать процент проектов, которые используют JUnit, историю создания, популярность в Интернете. Вместо этого я предлагаю сразу начать писать код.
Для того, чтобы начать писать тесты — нам нужен код, который мы будем этими тестами покрывать. Предлагаю создать простой Maven проект и написать в нем небольшой сервис. Я буду все делать в Intellij idea, но, как я говорю каждый раз: выбор среды программирования не имеет значения. Главное, чтобы Вам было удобно и понятно. Шаги по созданию проекта следующие: File->New->Project. Далее будет окно с выбором типа проекта:

Выбираем Maven и нажимаем Next. Далее заполняем groupId и artifactId значениями com.javamaster и junit_example соответственно.
JUnit — это сторонняя библиотека и ее нужно подключить. Просто добавим зависимость в pom.xml. В результате наш мавен файл стал:
Перед тестами я написал небольшой класс UsersService, который и выступит в качестве кода, который мы попытаемся покрыть тестами.
Код выше — очень простой пример, который не нуждается в дополнительных объяснениях. Если же он Вам по какой-то причине не понятен или очень сложный — я настоятельно советую ознакомиться со статьями Java для новичка.
Теперь приступим к написанию самих тестов.
JUnit тест — это простой класс java, методы которого помечены аннотацией @Test. Как правило, один метод отвечает за тестирование одного кейса. В библиотеке также предусмотрены и другие аннотации которые применяют для предварительной подготовки к тестированию: @BeforeClass, @Before, @AfterClass, @After. Их примеры я тоже покажу в коде. Также, в библиотеке есть готовый класс Assert, с помощью которого можно проводить сравнения фактических значений с ожидающими.
Теперь, создадим класс UsersServiceTest в директории src/main/test/java. Если Вы создавали проект строго по инструкции выше — эта директория должна быть. Но, часто такое бывает, что она отсутствует. В этом нет ничего страшного. Просто создайте ее руками. Структура проекта должна быть примерно как на изображении ниже.

Теперь сам код теста:
Как видно по коду выше, первое, что я сделал — добавил необходимые мне классы и произвел предварительную настройку перед тестом. Я добавил переменную UsersService, ведь именно этот класс я и планирую протестировать. Далее я добавил
Аннотация Rule в JUnit 4 — это компонент, который перехватывает вызовы тестового метода и позволяет нам что-то делать до запуска тестового метода и после запуска тестового метода.
Класс ExpectedException — это тоже из библиотеки JUnit. Правило ExpectedException позволяет вам проверить, что ваш код вызывает конкретное исключение. А если хотите проще: используйте конструкцию выше, для «отлова» нужных Вам исключительних ситуаций.
Далее идут сами методы, которые тестируют функциональность класса UsersService. Из названий методов видно какой функционал они тестируют.
Иногда, бывает полезно не только настроить предварительные ресурсы перед тестированием, но и очистить некоторые из них. С этой задачей отлично позволяют справиться аннотации @AfterClass и @After. В данном примере им приминения не нашлось, но я создал их для примера.
Для запуска тестов нужно нажать правой кнопкой на классе и выбрать Run. Или запустить тест, нажав на зеленую кнопку в intellij idea. В eclipse механизм запуска должен быть похожим. Причем запускать можно как весь класс тестов, так и каждый тест по отдельности.
В результате успешного запуска и отработки тестов Вы должны увидеть в консоли примерно такой результат:

Цель тестов — выявить ошибки в программе на ранних стадиях, когда код еще не успел уйти в продакшин. Помните, не нужно подстраивать тесты под функционал или, что еще хуже — функционал под тесты. Если определенные тесты не проходят — нужно обратить внимание на бизнес логику, ошибки в коде. Перед этим нужно внимательно ознакомиться с результатом теста и понять, что же все-таки не так.
Возьмем для примера метод isBirthDay. Его функционал и назначение понятны: метод должен возвращать есть ли у пользователя день рождение в зависимости от даты рождения и входной даты. Почему я использовал входную дату вместо использования например текущей даты? Дело в том, что я не знаю когда будут запускаться данные тесты. И может быть такой вариант, что запуск тестов в определенную дату даст нам неверный результат их работы.
Функционал isBirthDay покрывают два теста:
Если бы вместо даты сравнения я использовал бы текущую дату, запуск теста 2 месяца 1 дня — вернул бы true в то время, когда я ожидал совсем другое.
Вернемся к нашему експерименту. Сейчас мы увидим, почему так важно иметь тесты на существующий функционал. Особенно перед тем как потом этот функционал будет изменен. Часто так бывает, что над проектом работал один человек, потом другой, далее проект попадает к другим людям и возникает необходимость изменить уже существующий функционал или его часть.
Допустим, Вас попросили изменить реализацию метода isBirthDay. Возможно, пример примитивный и простой, но в целях учебы вполне себе сойдет.
Вы что-то там делали и написали вот такое решение:
Можете думать, что данный пример я выдумал, но в свое время, у нас был метод в приложении, который определял есть ли день рождения у пользователя. Причем, отрабатывал шедулер, который выбирал из базы данных пользователей, брал дату их рождения и потом отсылал поздравление на почту. Проблема была в том, что пользователей было примерно пол миллиона, а день рождения у них хранился не в очень удобном для java формате. Код поздравлений с днем рождения отрабатывал очень медленно. Программист, который его написал явно был не очень опытным: он брал из базы дату рождения пользователя в виде строки, потом вынимал из строки день и месяц, и сравнивал их с текущим днем и месяцем.
В результате, мы пришли к решению, что код нужно оптимизировать. Это дело поручили одному программисту, который и предложил сравнивать дату рождения пользователя с текущей :). Удивительно, но тестов на тот функционал не было ни до, ни после «оптимизации». Вот он пришел ко мне примерно с таким кодом:
и говорит: «Не понимаю, в базе данных так много пользователей но пока никому не отправилось поздравление». Вот такой вот казус случился однажды с реальным приложением. А были бы тесты — они бы все показали.
Давайте попробуем запустить тесты и посмотреть, что же будет отрабатывать когда мы используем такое решение для наших именинников:

Как видно на изображении выше — тесты очень хорошо справились с поставленной задачей.
У Вас часто будет возникать вопрос: сколько нужно тестов, чтобы убедиться в правильности написанного кода? На это нет конкретного ответа. Старайтесь писать столько тестов, сколько сами считаете нужным. На реальных проектах Вы будете писать столько, на сколько будет хватать времени. Я советую покрывать тестами некоторые подозрительные и опасные места в коде. Особено тщательно нужно покрывать места, где идет работа кода с финансами, округлениями. Как показывает опыт, именно они наиболее часто дают ошибки.
Это все, что касается юнит тестирования и, в частности, написания JUnit тестов на Java.
Основы JUnit
Когда делаешь первые попытки писать юнит-тесты обычно обычно сталкиваешься с проблемой начинания: вроде бы документация прочитана, цель ясна, а с чего начинать — не понятно.
Попробуем вместе написать простой юнит-тест, для более-менее настоящего класса, в котором испытаем почти весь базовый функционал JUnit.
Подготовка
Создадим пустой maven проект:
Класс для тестирования
Поскольку я обещал почти настоящий пример, придётся написать хоть сколько-то полезный класс. Пускай это будем набор утилит для работы со строками:
Тесты
Название тестовых методов так же могут быть любыми, однако для повышения читаемости кода, рекомендуется начинать их с префикса test * и отражать в названии суть теста.
Первый юнит-тест
В первом юнит-тесте строка
и есть входные данные, которые мы отдаём в проверяемую функцию.
Эталонные данные определены в следующей строке:
Вызываем проверяемый код и сохраняем результат его работы:
Наконец самая главная часть теста, проверка:
Однако с сообщением результаты тестирования становятся гораздо приятнее при чтении.
Более того, сам юнит-тест уже является краткой и понятной документацией к функции. В четырёх строках чётко и однозначно написано, как ведёт себя функция: возвращает новый строковый объект, значение которого является переданным ей числом с плавающей запятой, записанное в десятичной системе счисления.
А самый главный бонус юнит-тестирования, это фиксация поведения кода. Вы знаете, прямо сейчас, что функция ведёт себя определённым образом. И код, который её использует, полагается на это поведение. Если Когда вы захотите изменить эту функцию, юнит-тест будет вам гарантировать, что
поведение функции осталось таким же (либо тест провалится). Следовательно остальной код не заметит изменения реализации функции, а это значит, что с этого момента вы можете спокойной менять любую часть кода: юнит-тесты не позволят вам что-нибудь сломать.
Второй юнит-тест
Следующий юнит-тест напишем для обратной функции преобразования строки в число с плавающей запятой:
Краткое сравнение JUnit и TestNG
Привет, Хабр. Для будущих студентов курса «Java QA Automation Engineer» и всех интересующихся темой тестирования подготовили перевод материала.
Также приглашаем посетить открытый вебинар «Паттерн PageObject». Чтобы автотесты не приходилось перечитывать и рефакторить, нужно сразу продумывать их архитектуру. Тут на помощь приходят паттерны. Участники вебинара вместе с экспертом познакомятся с самым популярным из них.
1. Обзор
JUnit и TestNG, несомненно, являются двумя наиболее популярными фреймворками для модульного тестирования (юнит-тестирования) в экосистеме Java. Хотя JUnit послужил вдохновением для TestNG, второй имеет ряд отличий и, в отличие от JUnit, работает для функционального и более высоких уровней тестирования.
В этой статье мы обсудим и сравним эти фреймворки, рассмотрев их функции и распространенные варианты использования.
2. Настройка теста
При написании тест-кейсов перед выполнением самого теста нам часто необходимо выполнить некоторые инструкции по настройке или инициализации, а также провести очистку после завершения тестов. Давайте взглянем на них в обоих фреймворках.
JUnit предлагает инициализацию и очистку на двух уровнях, до и после каждого метода и класса. У нас есть аннотации @BeforeEach, @AfterEach на уровне метода и @BeforeAll и @AfterAll на уровне класса:
Обратите внимание, что в этом примере используется JUnit 5. В предыдущей версии JUnit 4 нам нужно было бы использовать аннотации @Before и @After, которые эквивалентны @BeforeEach и @AfterEach. Точно так же, @BeforeAll и @AfterAll являются заменой для @BeforeClass и @AfterClass в JUnit 4.
Подобно JUnit, TestNG также обеспечивает инициализацию и очистку на уровне метода и класса. Хотя на уровне класса @BeforeClass и @AfterClass остаются неизменными, аннотациями уровня метода являются @BeforeMethod и @AfterMethod:
TestNG также предлагает аннотации @BeforeSuite, @AfterSuite, @BeforeGroup и @AfterGroup для конфигураций на уровне набора (suite) и группы:
Кроме того, мы можем использовать @BeforeTest и @AfterTest, если нам нужна какая-либо конфигурация до или после тест-кейсов, включенных в тег в XML-файле конфигурации TestNG:
Обратите внимание, что объявление методов @BeforeClass и @AfterClass в JUnit должно быть статическим. Для сравнения, объявление этих методов в TestNG не имеет таких ограничений.
3. Игнорирование тестов
Обе платформы поддерживают игнорирование тест-кейсов, хотя делают это по-разному. JUnit предлагает аннотацию @Ignore:
в то время как TestNG использует @Test с параметром «enabled» с логическим значением true или false :
4. Совместное выполнение тестов
Совместное выполнение тестов в виде коллекции возможно как в JUnit, так и в TestNG, но они делают это по-разному.
В JUnit 5 мы можем использовать аннотации @RunWith, @SelectPackages и @SelectClasses для группировки тест-кейсов и запуска их как набора. Набор — это коллекция тест-кейсов, которые мы можем сгруппировать и запустить как единый тест.
Если мы хотим сгруппировать тест-кейсы различных пакетов для запуска вместе в Suite нам нужно использовать аннотацию @SelectPackages :
Если мы хотим, чтобы определенные тестовые классы работали вместе, JUnit 5 обеспечивает нам такую гибкость с помощью @SelectClasses:
Ранее, в JUnit 4 мы добивались группировки и одновременного выполнения нескольких тестов с помощью аннотации @Suite:
В TestNG мы можем группировать тесты с помощью файла XML:
Это означает, что RegistrationTest и SignInTest будут работать вместе.
Помимо группировки классов, TestNG также может группировать методы с помощью аннотации @Test (groups = «groupName») :
Попробуем использовать XML для запуска группы:
Будет выполнен тестовый метод с тегом группы regression.
5. Тестирование исключений
Функция тестирования исключений с использованием аннотаций доступна как в JUnit, так и в TestNG.
Давайте сначала создадим класс с методом, который выдает исключение:
В JUnit 5 для тестирования исключений мы можем использовать API assertThrows :
В JUnit 4 мы можем добиться этого, используя @Test ( expected = DivideByZeroException.class ) поверх тестового API.
И с TestNG мы также можем реализовать то же самое:
Эта функция подразумевает выброс исключения из фрагмента кода, который является частью теста.
6. Параметризованные тесты
Параметризованные модульные тесты полезны для тестирования одного и того же кода в разных условиях. С помощью параметризованных модульных тестов мы можем настроить метод тестирования, который получает данные из некоторого источника данных. Основная идея состоит в том, чтобы сделать метод модульного тестирования повторно используемым и тестировать с другим набором входных данных.
В JUnit 5 у нас есть преимущество в том, что методы тестирования используют аргументы данных непосредственно из настроенного источника. По умолчанию JUnit 5 предоставляет несколько source-аннотаций, например:
@ValueSource : мы можем использовать это с массивом значений типа Short , Byte , Int , Long , Float , Double , Char и String :
@EnumSource — передает Enum-константы в качестве параметров методу тестирования:
@MethodSource — передает (passes) внешние методы, генерирующие потоки:
@CsvSource — использует значения CSV в качестве источника для параметров:
Точно так же у нас есть другие источники, такие как @CsvFileSource , если нам нужно прочитать CSV-файл из classpath, и @ArgumentSource , чтобы указать настраиваемый многоразовый ArgumentsProvider .
В JUnit 4 тестовый класс должен быть аннотирован @RunWith , чтобы сделать его параметризованным классом, и @Parameter , чтобы использовать для обозначения значений параметров для модульного теста.
В TestNG мы можем параметризовать тесты с помощью аннотаций @Parameter или @DataProvider. При использовании XML-файла аннотируйте метод тестирования с помощью @Parameter :
и укажите данные в файле XML:
Хотя использование информации в файле XML просто и полезно, в некоторых случаях вам может потребоваться предоставить более сложные данные.
Для этого мы можем использовать аннотацию @DataProvider , которая позволяет нам отображать сложные типы параметров для методов тестирования.
Вот пример использования @DataProvider для примитивных типов данных:
И @DataProvider для объектов:
Таким же образом любые конкретные объекты, которые должны быть протестированы, могут быть созданы и возвращены с помощью поставщика данных. Это полезно при интеграции с такими фреймворками, как Spring.
Обратите внимание, что в TestNG, поскольку метод @DataProvider не обязательно должен быть статическим, мы можем использовать несколько методов поставщика данных в одном тестовом классе.
7. Тайм-аут теста
Тайм-аут тестов означает, что тестовый пример должен завершиться неудачно, если выполнение не будет завершено в течение определенного указанного периода. И JUnit, и TestNG поддерживают тесты с тайм-аутом. В JUnit 5 мы можем написать тест тайм-аута так:
В JUnit 4 и TestNG мы можем написать тот же тест, используя @Test (timeout = 1000)
8. Зависимые тесты
TestNG поддерживает зависимые тесты. Это означает, что в наборе методов тестирования, если начальный тест не пройден, все последующие зависимые тесты будут пропущены, а не помечены как неудачные, как в случае с JUnit.
Давайте посмотрим на сценарий, в котором нам нужно проверить электронную почту, и в случае успеха мы перейдем к входу в систему:
9. Порядок выполнения тестов
В JUnit 4 или TestNG не существует определенного неявного порядка, в котором методы тестирования будут выполняться. Методы вызываются только в том виде, в каком они возвращаются Java Reflection API. Начиная с JUnit 4, он использует более детерминированный, но не предсказуемый порядок.
Чтобы иметь больший контроль, мы аннотируем тестовый класс аннотацией @FixMethodOrder и упомянем сортировщик методов:
Параметр MethodSorters.NAME_ASCENDING сортирует методы по имени метода в лексикографическом порядке. Помимо этого сортировщика, у нас также есть MethodSorter.DEFAULT и MethodSorter.JVM .
TestNG также предоставляет несколько способов управления порядком выполнения тестовых методов. Мы предоставляем параметр priority (приоритета) в аннотации @Test:
Обратите внимание, что priority вызывает методы тестирования на основе приоритета, но не гарантирует, что тесты на одном уровне будут завершены до вызова со следующего уровня приоритета.
Иногда при написании функциональных тестовых примеров в TestNG у нас может быть взаимозависимый тест, в котором порядок выполнения должен быть одинаковым для каждого запуска теста. Для этого мы должны использовать параметр dependsOnMethods в аннотации @Test, как мы видели в предыдущем разделе.
10. Пользовательские имена тестов
Эта аннотация не дает никаких преимуществ при тестировании, но она позволяет легко читать и понимать результаты тестирования даже для нетехнических специалистов:
Каждый раз, когда мы запускаем тест, на выводе будет отображаться отображаемое имя вместо имени метода.
Прямо сейчас в TestNG нет возможности указать пользовательское имя.
11. Заключение
И JUnit, и TestNG — современные инструменты для тестирования в экосистеме Java.
В этой статье мы кратко рассмотрели различные способы написания тестов в каждой из этих двух тестовых сред.
Реализацию всех фрагментов кода можно найти в проектах TestNG и хjunit-5 на Github.



