JUnit 5 — это инфраструктура модульного тестирования для Java следующего поколения, оснащенная множеством интересных функций, включая вложенные тесты, параметризованные тесты, новый API расширения или поддержку Java 8 и многие другие.
В этой статье показаны основные концепции JUnit 5, включая жизненный цикл теста, внедрение параметров и утверждения (базовый, время ожидания и исключение).
Документация
Прежде всего, документация JUnit 5 просто великолепна и, на мой взгляд. Он содержит не только исчерпывающую документацию по фреймворку, но и множество примеров, в том числе множество примеров. Не пропустите документацию при изучении JUnit 5: http://junit.org/junit5/docs/current/user-guide/
зависимости
Во-первых, для запуска JUnit 5 требуется Java 8. В заключение. Это дает возможность использовать лямбда-выражения в тестах и сделать их более удобными (лямбда-выражения в основном используются в утверждениях). Во-вторых, JUnit 5 состоит из нескольких артефактов, сгруппированных по JUnit Platform, JUnit Jupiter и JUnit Vintage. Это может звучать страшно, но сегодня с такими инструментами, как Maven или Gradle, это не проблема, и для начала вам нужна отдельная зависимость. Базовая конфигурация Gradle может выглядеть следующим образом:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
 | 
buildscript {    ext {        junitPlatformVersion = '1.0.1'        junitJupiterVersion = '5.0.1'    }    repositories {        mavenCentral()    }    dependencies {        classpath "org.junit.platform:junit-platform-gradle-plugin:${junitPlatformVersion}"    }}apply plugin: 'java'apply plugin: 'org.junit.platform.gradle.plugin'sourceCompatibility = 1.8repositories {    mavenCentral()}dependencies {     testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")}task wrapper(type: Wrapper) {    gradleVersion = '4.1'} | 
JUnit 5 тестовых классов и методов
 Общие тестовые аннотации, используемые в тестовом классе (импортированные из org.junit.jupiter.api ): 
-   
@BeforeAll— выполняется перед всеми методами в тесте -   
@BeforeEach— выполнять перед каждым тестовым методом в тестовом классе -   
@Test— актуальный метод тестирования -   
@AfterEach— выполняется после каждого метода теста в тесте -   
@AfterAll— выполняется после всех методов в тесте 
Другие основные, но полезные аннотации:
-   
@DisplayName— пользовательское отображаемое имя для тестового класса или метода -   
@Disabled— отключение тестового класса или метода -   
@RepeatedTest— сделать тестовый шаблон из тестового метода -   
@Tag— пометить тестовый класс или метод для дальнейшего выбора теста 
Основной пример:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
 | 
import org.junit.jupiter.api.*;@DisplayName("JUnit5 - Test basics")class JUnit5Basics {    @BeforeAll    static void beforeAll() {        System.out.println("Before all tests (once)");    }    @BeforeEach    void beforeEach() {        System.out.println("Runs before each test");    }    @Test    void standardTest() {        System.out.println("Test is running");    }    @DisplayName("My #2 JUnit5 test")    @Test    void testWithCustomDisplayName() {        System.out.println("Test is running");    }    @DisplayName("Tagged JUnit5 test ")    @Tag("cool")    @Test    void tagged() {        System.out.println("Test is running");    }    @Disabled("Failing due to unknown reason")    @DisplayName("Disabled test")    @Test    void disabledTest() {        System.out.println("Disabled, will not show up");    }    @DisplayName("Repeated test")    @RepeatedTest(value = 2, name = "#{currentRepetition} of {totalRepetitions}")    void repeatedTestWithRepetitionInfo() {        System.out.println("Repeated test");    }    @AfterEach    void afterEach() {        System.out.println("Runs after each test");    }} | 
Обратите внимание, что тестовые классы и методы не должны быть общедоступными — они могут быть закрытыми .
Жизненный цикл выполнения теста
  В JUnit 5 по умолчанию новый экземпляр теста создается для каждого метода теста в классе теста.  Это поведение можно настроить с @TestInstance аннотации уровня @TestInstance : 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
 | 
import org.junit.jupiter.api.*;@TestInstance(TestInstance.Lifecycle.PER_CLASS)@DisplayName("JUnit5 - Test lifecycle adjustments")class JUnit5PerClassLifecycle {    private Object first = new Object();    private Object second;    @BeforeAll    void beforeAll() {        this.second = this.first;        System.out.println("Non static before all.");    }    @BeforeEach    void beforeEach() {        Assertions.assertEquals(first, second);    }    @Test    void first() {        Assertions.assertEquals(first, second);    }    @Test    void second() {        Assertions.assertEquals(first, second);    }    @AfterAll    void afterAll() {        System.out.println("Non static after all.");    }    @AfterEach    void afterEach() {        Assertions.assertEquals(first, second);    }} | 
  В режиме PER_CLASS для всех тестов создается один экземпляр теста, и @BeforeAll и @AfterAll больше не должны быть статическими. 
Разрешение параметра
  Методы тестирования и обратного вызова теперь могут принимать аргументы, такие как org.junit.jupiter.api.TestInfo , org.junit.jupiter.api.RepetitionInfo или org.junit.jupiter.api.TestReporter . 
  Кроме того, благодаря действительно простому, но мощному API расширения JUnit 5, разрешение пользовательских параметров в методах является вопросом обеспечения собственной реализации org.junit.jupiter.api.extension.ParameterResolver . 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
 | 
class JUnit5BuiltInParameterResolution {    @BeforeAll    static void beforeAll(TestInfo testInfo) {        System.out.println("Before all can take parameters. Started: " + testInfo.getDisplayName());    }    @BeforeAll    static void beforeAll(TestReporter testReporter) {        testReporter.publishEntry("myEntry", "myValue");    }    @BeforeAll    static void beforeAll(TestInfo testInfo, TestReporter testReporter) {        testReporter.publishEntry("myOtherEntry", testInfo.getDisplayName());    }    @BeforeEach    void beforeEach(TestInfo testInfo) {    }    @Test    void standardTest(TestInfo testInfo) {    }    @DisplayName("Repeated test")    @RepeatedTest(value = 2, name = "#{currentRepetition} of {totalRepetitions}")    void repeatedTest(RepetitionInfo repetitionInfo) {        System.out.println("Repeated test - " + repetitionInfo.toString());    }    @AfterAll    static void afterAll() {    }    @AfterAll    static void afterAll(TestInfo testInfo) {    }    @AfterEach    void afterEach() {    }} | 
Утверждения
  JUnit 5 поставляется со многими стандартными утверждениями, которые можно найти в классе org.junit.jupiter.api.Assertions . 
Основные утверждения
  Основные утверждения: assertEquals , assertArrayEquals , assertSame , assertNotSame , assertTrue , assertFalse , assertNull , assertNotNull , assertLinesMatch , assertIterablesMatch 
Пример:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
 | 
@Testvoid basicAssertions() {    // arrange    List<String> owners = Lists.newArrayList("Betty Davis", "Eduardo Rodriquez");    // assert    assertNotNull(owners);    assertSame(owners, owners);    assertFalse(owners::isEmpty); // Lambda expression    assertEquals(2, owners.size(), "Found owner names size is incorrect");    assertLinesMatch(newArrayList("Betty Davis", "Eduardo Rodriquez"), owners);    assertArrayEquals(        new String[]{"Betty Davis", "Eduardo Rodriquez"},         owners.toArray(new String[0])    );} | 
Утвердить все
  Assertions.assertAll утверждает, что все предоставленные исполняемые файлы не генерируют исключения: 
| 
 1 
2 
3 
4 
 | 
Assertions.assertAll(    () -> Assertions.assertNotNull(null, "May not be null"),    () -> Assertions.assertTrue(false, "Must be true")); | 
Выше будет сообщать о нескольких сбоях:
| 
 1 
2 
3 
 | 
org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)    May not be null ==> expected: not <null>    Must be true | 
Примечание: вы можете прочитать об альтернативах в JUnit 4 и AssertJ — http://blog.codeleak.pl/2015/09/assertjs-softassertions-do-we-need-them.html
Утверждения тайм-аута
  Утверждения тайм-аута используются для проверки того, что время выполнения задачи не превышено.  Существует два варианта подтверждения тайм-аута: assertTimeout и assertTimeoutPreemptively .  Оба берут два 
- Выполните задачу синхронно, ожидая ее завершения и затем устанавливая таймауты:
 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
 | 
@Testvoid assertTimeout() {    // arrange    Executable task = () -> Thread.sleep(1000);    // waits for the task to finish before failing the test    Assertions.assertTimeout(Duration.ofMillis(100), task::execute);}@Testvoid assertTimeoutWithThrowingSupplier() {    // arrange    ThrowingSupplier<String> task = () -> "result";    // waits for the task to finish before failing the test    Assertions.assertTimeout(Duration.ofMillis(100), task::get);} | 
- Выполните задачу асинхронно (в новом потоке), прервите выполнение по истечении времени ожидания:
 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
 | 
@Testvoid assertTimeoutPreemptively() {    // arrange    Executable task = () -> Thread.sleep(1000);    // abort execution when timeout exceeded    Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), task::execute);}@Testvoid assertTimeoutPreemptivelyWithThrowingSupplier() {    // arrange    ThrowingSupplier<String> task = () -> "result";    // abort execution when timeout exceeded, return the result    String result = Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), task::get);    Assertions.assertEquals("result", result);} | 
Исключения
  Встроенный в JUnit 5 assertThrows получает ожидаемый тип исключения в качестве первого параметра, а исполняемый файл (функциональный интерфейс) потенциально вызывает исключение как второй.  Метод завершится ошибкой, если не будет сгенерировано исключение или исключение другого типа.  Метод возвращает само исключение, которое можно использовать для дальнейших утверждений: 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
 | 
@Testvoid assertException() {    // arrange    Executable throwingExecutable = () -> {        throw new RuntimeException("Unexpected error!");    };    // act and assert    RuntimeException thrown = Assertions.assertThrows(        RuntimeException.class, throwingExecutable::execute, "???"    );    Assertions.assertAll(        () -> Assertions.assertEquals("Unexpected error!", thrown.getMessage()),        () -> Assertions.assertNotNull(thrown.getCause())    );} | 
Примечание: вы можете прочитать об альтернативах в JUnit 4 — http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html
Резюме
JUnit 5 содержит множество функций. В этой статье были продемонстрированы только основы, но этого должно быть достаточно, чтобы вы начали писать свои первые тесты JUnit 5.
Смотрите также
- Очистить параметризованные тесты с помощью JUnit 5 — http://blog.codeleak.pl/2017/06/cleaner-parameterized-tests-with-junit-5.html
 
|   Смотреть оригинальную статью здесь: JUnit 5 — Основы 
 Мнения, высказанные участниками Java Code Geeks, являются их собственными.  |