Мигриране от JUnit 4 към JUnit 5

1. Общ преглед

В тази статия ще видим как можем да мигрираме от JUnit 4 към най-новата версия на JUnit 5 - с преглед на разликите между двете версии на библиотеката.

За общите насоки за използване на JUnit 5 вижте нашата статия тук.

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

Нека започнем с предишната версия - JUnit 4 има някои ясни ограничения:

  • Цялата рамка се съдържаше в библиотека с един буркан. Цялата библиотека трябва да бъде импортирана, дори когато се изисква само определена функция. В 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 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") @RunWith(JUnitPlatform.class) public class AnnotationTestExampleTest { /*...*/ }

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

   maven-surefire-plugin   junit5     

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 .

For example, say we have a custom rule in JUnit 4 to write log traces before and after a test:

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 ... } }; } }

And we implement it in a test suite:

@Rule public TraceUnitTestRule traceRuleTests = new TraceUnitTestRule(); 

In JUnit 5, we can write the same in a much more intuitive manner:

public class TraceUnitExtension implements AfterEachCallback, BeforeEachCallback { @Override public void beforeEach(TestExtensionContext context) throws Exception { // ... } @Override public void afterEach(TestExtensionContext context) throws Exception { // ... } }

Using JUnit 5's AfterEachCallback and BeforeEachCallback interfaces available in the package org.junit.jupiter.api.extension, we easily implement this rule in the test suite:

@RunWith(JUnitPlatform.class) @ExtendWith(TraceUnitExtension.class) public class RuleExampleTest { @Test public void whenTracingTests() { /*...*/ } }

3.7. JUnit 5 Vintage

JUnit Vintage aids in the migration of JUnit tests by running JUnit 3 or JUnit 4 tests within the JUnit 5 context.

We can use it by importing the JUnit Vintage Engine:

 org.junit.vintage junit-vintage-engine ${junit5.vintage.version} test 

4. Conclusion

Както видяхме в тази статия, JUnit 5 е модулен и модерен подход към рамката на JUnit 4. Въведохме основните разлики между тези две версии и загатнахме как да мигрираме от една в друга.

Пълното изпълнение на този урок може да бъде намерено в над на GitHub.