Перейти к основному содержимому

Переход с JUnit 4 на JUnit 5

· 5 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

В этой статье мы увидим, как мы можем перейти с JUnit 4 на последнюю версию JUnit 5 — с обзором различий между двумя версиями библиотеки.

Общие рекомендации по использованию JUnit 5 см. в нашей статье здесь .

2. Преимущества JUnit 5

Начнем с предыдущей версии — JUnit 4 имеет ряд явных ограничений:

  • Вся структура содержалась в одной библиотеке jar. Всю библиотеку необходимо импортировать, даже если требуется только конкретная функция. В JUnit 5 мы получаем больше детализации и можем импортировать только то, что необходимо
  • Один исполнитель тестов может одновременно выполнять тесты только в JUnit 4 (например , SpringJUnit4ClassRunner или Parameterized ). JUnit 5 позволяет нескольким исполнителям работать одновременно
  • JUnit 4 так и не продвинулся дальше Java 7, упустив множество функций из Java 8. JUnit 5 хорошо использует функции Java 8.

Идея JUnit 5 заключалась в том, чтобы полностью переписать JUnit 4, чтобы устранить большинство этих недостатков.

3. Отличия

JUnit 4 был разделен на модули, составляющие JUnit 5:

  • Платформа JUnit — этот модуль охватывает все платформы расширений, которые могут нас заинтересовать в выполнении тестов, обнаружении и составлении отчетов.
  • JUnit Vintage — этот модуль обеспечивает обратную совместимость с JUnit 4 или даже с JUnit 3.

3.1. Аннотации

JUnit 5 содержит важные изменения в своих аннотациях. Наиболее важным из них является то, что мы больше не можем использовать аннотацию @Test для указания ожиданий.

Ожидаемый параметр в JUnit 4 :

@Test(expected = Exception.class)
public void shouldRaiseAnException() throws Exception {
// ...
}

Теперь мы можем использовать метод assertThrows :

public void shouldRaiseAnException() throws Exception {
Assertions.assertThrows(Exception.class, () -> {
//...
});
}

Атрибут тайм -аута в JUnit 4:

@Test(timeout = 1)
public void shouldFailBecauseTimeout() throws InterruptedException {
Thread.sleep(10);
}

Теперь метод assertTimeout в JUnit 5:

@Test
public void shouldFailBecauseTimeout() throws InterruptedException {
Assertions.assertTimeout(Duration.ofMillis(1), () -> Thread.sleep(10));
}

Другие аннотации, которые были изменены в JUnit 5:

  • @Before аннотация переименована в @BeforeEach
  • @After аннотация переименована в @AfterEach
  • Аннотация @BeforeClass переименована в @BeforeAll
  • Аннотация @AfterClass переименована в @AfterAll
  • Аннотация @Ignore переименована в @Disabled

3.2. Утверждения

Теперь мы можем писать сообщения об утверждениях в лямбда-выражении в JUnit 5, позволяя ленивой оценке пропускать построение сложных сообщений до тех пор, пока они не понадобятся:

@Test
public void shouldFailBecauseTheNumbersAreNotEqual_lazyEvaluation() {
Assertions.assertTrue(
2 == 3,
() -> "Numbers " + 2 + " and " + 3 + " are not equal!");
}

Мы также можем группировать утверждения в JUnit 5:

@Test
public void shouldAssertAllTheGroup() {
List<Integer> list = Arrays.asList(1, 2, 4);
Assertions.assertAll("List is not incremental",
() -> Assertions.assertEquals(list.get(0).intValue(), 1),
() -> Assertions.assertEquals(list.get(1).intValue(), 2),
() -> Assertions.assertEquals(list.get(2).intValue(), 3));
}

3.3. Предположения

Новый класс предположений теперь находится в org.junit.jupiter.api.Assumptions . JUnit 5 полностью поддерживает существующие методы предположений в JUnit 4, а также добавляет набор новых методов, позволяющих выполнять некоторые утверждения только в определенных сценариях:

@Test
public void whenEnvironmentIsWeb_thenUrlsShouldStartWithHttp() {
assumingThat("WEB".equals(System.getenv("ENV")),
() -> {
assertTrue("http".startsWith(address));
});
}

3.4. Тегирование и фильтрация

В JUnit 4 мы могли группировать тесты, используя аннотацию @Category . В JUnit 5 аннотация @Category заменяется аннотацией @Tag :

@Tag("annotations")
@Tag("junit5")
public class AnnotationTestExampleTest {
/*...*/
}

Мы можем включать/исключать определенные теги с помощью maven-surefire-plugin :

<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<includeTags>junit5</includeTags>
</properties>
</configuration>
</plugin>
</plugins>
</build>

3.5. Новые аннотации для запуска тестов

@RunWith использовался для интеграции тестового контекста с другими фреймворками или для изменения общего потока выполнения тестов в JUnit 4.

В JUnit 5 теперь мы можем использовать аннотацию @ExtendWith для предоставления аналогичной функциональности.

Например, чтобы использовать функции Spring в JUnit 4:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
{"/app-config.xml", "/test-data-access-config.xml"})
public class SpringExtensionTest {
/*...*/
}

Теперь в JUnit 5 это простое расширение:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(
{ "/app-config.xml", "/test-data-access-config.xml" })
public class SpringExtensionTest {
/*...*/
}

3.6. Аннотации новых правил тестирования

В JUnit 4 аннотации @Rule и @ClassRule использовались для добавления специальных функций в тесты.

В JUnit 5 мы можем воспроизвести ту же логику, используя аннотацию @ExtendWith .

Например, скажем, у нас есть пользовательское правило в JUnit 4 для записи трассировки журнала до и после теста:

public class TraceUnitTestRule implements TestRule {

@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// Before and after an evaluation tracing here
...
}
};
}
}

И мы реализуем это в наборе тестов:

@Rule
public TraceUnitTestRule traceRuleTests = new TraceUnitTestRule();

В JUnit 5 мы можем написать то же самое гораздо более интуитивно понятным образом:

public class TraceUnitExtension implements AfterEachCallback, BeforeEachCallback {

@Override
public void beforeEach(TestExtensionContext context) throws Exception {
// ...
}

@Override
public void afterEach(TestExtensionContext context) throws Exception {
// ...
}
}

Используя интерфейсы AfterEachCallback и BeforeEachCallback JUnit 5, доступные в пакете org.junit.jupiter.api.extension, мы легко реализуем это правило в наборе тестов:

@ExtendWith(TraceUnitExtension.class)
public class RuleExampleTest {

@Test
public void whenTracingTests() {
/*...*/
}
}

3.7. Юнит 5 Винтаж

JUnit Vintage помогает в миграции тестов JUnit, запуская тесты JUnit 3 или JUnit 4 в контексте JUnit 5.

Мы можем использовать его, импортировав JUnit Vintage Engine:

<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit5.vintage.version}</version>
<scope>test</scope>
</dependency>

4. Вывод

Как мы видели в этой статье, JUnit 5 представляет собой модульную и современную версию платформы JUnit 4. Мы представили основные различия между этими двумя версиями и намекнули, как перейти с одной на другую.

Полную реализацию этого руководства можно найти на GitHub .