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.