Привет, Хабр. Для будущих студентов курса "Java QA Automation Engineer" и всех интересующихся темой тестирования подготовили перевод материала.Также приглашаем посетить открытый вебинар «Паттерн PageObject». Чтобы автотесты не приходилось перечитывать и рефакторить, нужно сразу продумывать их архитектуру. Тут на помощь приходят паттерны. Участники вебинара вместе с экспертом познакомятся с самым популярным из них. JUnit и TestNG, несомненно, являются двумя наиболее популярными фреймворками для модульного тестирования (юнит-тестирования) в экосистеме Java. Хотя JUnit послужил вдохновением для TestNG, второй имеет ряд отличий и, в отличие от JUnit, работает для функционального и более высоких уровней тестирования. В этой статье мы обсудим и сравним эти фреймворки, рассмотрев их функции и распространенные варианты использования. При написании тест-кейсов перед выполнением самого теста нам часто необходимо выполнить некоторые инструкции по настройке или инициализации, а также провести очистку после завершения тестов. Давайте взглянем на них в обоих фреймворках. 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 не имеет таких ограничений. Обе платформы поддерживают игнорирование тест-кейсов, хотя делают это по-разному. JUnit предлагает аннотацию @Ignore: в то время как TestNG использует @Test с параметром «enabled» с логическим значением true или false: Совместное выполнение тестов в виде коллекции возможно как в 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. Функция тестирования исключений с использованием аннотаций доступна как в JUnit, так и в TestNG. Давайте сначала создадим класс с методом, который выдает исключение: В JUnit 5 для тестирования исключений мы можем использовать API assertThrows: В JUnit 4 мы можем добиться этого, используя @Test (expected = DivideByZeroException.class) поверх тестового API. И с TestNG мы также можем реализовать то же самое: Эта функция подразумевает выброс исключения из фрагмента кода, который является частью теста. Параметризованные модульные тесты полезны для тестирования одного и того же кода в разных условиях. С помощью параметризованных модульных тестов мы можем настроить метод тестирования, который получает данные из некоторого источника данных. Основная идея состоит в том, чтобы сделать метод модульного тестирования повторно используемым и тестировать с другим набором входных данных. В 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 не обязательно должен быть статическим, мы можем использовать несколько методов поставщика данных в одном тестовом классе. Тайм-аут тестов означает, что тестовый пример должен завершиться неудачно, если выполнение не будет завершено в течение определенного указанного периода. И JUnit, и TestNG поддерживают тесты с тайм-аутом. В JUnit 5 мы можем написать тест тайм-аута так: В JUnit 4 и TestNG мы можем написать тот же тест, используя @Test (timeout = 1000) TestNG поддерживает зависимые тесты. Это означает, что в наборе методов тестирования, если начальный тест не пройден, все последующие зависимые тесты будут пропущены, а не помечены как неудачные, как в случае с JUnit. Давайте посмотрим на сценарий, в котором нам нужно проверить электронную почту, и в случае успеха мы перейдем к входу в систему: В JUnit 4 или TestNG не существует определенного неявного порядка, в котором методы тестирования будут выполняться. Методы вызываются только в том виде, в каком они возвращаются Java Reflection API. Начиная с JUnit 4, он использует более детерминированный, но не предсказуемый порядок. Чтобы иметь больший контроль, мы аннотируем тестовый класс аннотацией @FixMethodOrder и упомянем сортировщик методов: Параметр MethodSorters.NAME_ASCENDING сортирует методы по имени метода в лексикографическом порядке. Помимо этого сортировщика, у нас также есть MethodSorter.DEFAULT и MethodSorter.JVM. TestNG также предоставляет несколько способов управления порядком выполнения тестовых методов. Мы предоставляем параметр priority (приоритета) в аннотации @Test: Обратите внимание, что priority вызывает методы тестирования на основе приоритета, но не гарантирует, что тесты на одном уровне будут завершены до вызова со следующего уровня приоритета. Иногда при написании функциональных тестовых примеров в TestNG у нас может быть взаимозависимый тест, в котором порядок выполнения должен быть одинаковым для каждого запуска теста. Для этого мы должны использовать параметр dependsOnMethods в аннотации @Test, как мы видели в предыдущем разделе. По умолчанию всякий раз, когда мы запускаем тест, тестовый класс и имя тестового метода выводится в консоли или IDE. JUnit 5 предоставляет уникальную функцию, в которой мы можем упоминать настраиваемые описательные имена для классов и методов тестирования с помощью аннотации @DisplayName. Эта аннотация не дает никаких преимуществ при тестировании, но она позволяет легко читать и понимать результаты тестирования даже для нетехнических специалистов: Каждый раз, когда мы запускаем тест, на выводе будет отображаться отображаемое имя вместо имени метода. Прямо сейчас в TestNG нет возможности указать пользовательское имя. И JUnit, и TestNG — современные инструменты для тестирования в экосистеме Java. В этой статье мы кратко рассмотрели различные способы написания тестов в каждой из этих двух тестовых сред. Реализацию всех фрагментов кода можно найти в проектах TestNG и хjunit-5 на Github. Узнать подробнее о курсе "Java QA Automation Engineer". Смотреть открытый вебинар «Паттерн PageObject».  Редактор