Migrazione da JUnit 4 a JUnit 5

1. Panoramica

In questo articolo vedremo come migrare da JUnit 4 all'ultima versione di JUnit 5, con una panoramica delle differenze tra le due versioni della libreria.

Per le linee guida generali sull'utilizzo di JUnit 5, vedere il nostro articolo qui.

2. Vantaggi di JUnit 5

Cominciamo con la versione precedente - JUnit 4 ha alcuni chiari limiti:

  • L'intero framework era contenuto in una singola libreria jar. L'intera libreria deve essere importata anche quando è richiesta solo una particolare funzionalità. In JUnit 5, otteniamo una maggiore granularità e possiamo importare solo ciò che è necessario
  • Un test runner può eseguire solo test in JUnit 4 alla volta (ad esempio SpringJUnit4ClassRunner o Parameterized ). JUnit 5 consente a più corridori di lavorare contemporaneamente
  • JUnit 4 non è mai avanzato oltre Java 7, perdendo molte funzionalità da Java 8. JUnit 5 fa buon uso delle funzionalità di Java 8

L'idea alla base di JUnit 5 era di riscrivere completamente JUnit 4 per risolvere la maggior parte di questi inconvenienti.

3. Differenze

JUnit 4 è stata suddivisa in moduli che comprendono JUnit 5:

  • Piattaforma JUnit: questo modulo si occupa di tutti i framework di estensione che potrebbero interessarci all'esecuzione dei test, alla scoperta e al reporting
  • JUnit Vintage: questo modulo consente la retrocompatibilità con JUnit 4 o anche JUnit 3

3.1. Annotazioni

JUnit 5 include importanti modifiche all'interno delle sue annotazioni. Il più importante è che non possiamo più usare l' annotazione @Test per specificare le aspettative.

Il parametro previsto in JUnit 4:

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

Ora possiamo usare un metodo assertThrows :

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

L' attributo timeout in JUnit 4:

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

Ora, il metodo assertTimeout in JUnit 5:

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

Altre annotazioni che sono state modificate all'interno di JUnit 5:

  • L' annotazione @Before viene rinominata in @BeforeEach
  • L' annotazione @After viene rinominata in @AfterEach
  • L' annotazione @BeforeClass viene rinominata @BeforeAll
  • L' annotazione @AfterClass viene rinominata @AfterAll
  • L' annotazione @Ignore viene rinominata in @Disabled

3.2. Asserzioni

Ora possiamo scrivere messaggi di asserzione in un lambda in JUnit 5, consentendo alla valutazione pigra di saltare la costruzione di messaggi complessi fino a quando non è necessario:

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

Possiamo anche raggruppare le asserzioni in 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. Presupposti

La nuova classe Assumptions è ora in org.junit.jupiter.api.Assumptions . JUnit 5 supporta completamente i metodi di ipotesi esistenti in JUnit 4 e aggiunge anche una serie di nuovi metodi per consentire l'esecuzione di alcune asserzioni solo in scenari specifici:

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

3.4. Applicazione di tag e filtri

In JUnit 4 potremmo raggruppare i test utilizzando l' annotazione @Category . Con JUnit 5, l' annotazione @Category viene sostituita con l' annotazione @Tag :

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

Possiamo includere / escludere tag particolari utilizzando il plug-in maven-surefire :

   maven-surefire-plugin   junit5     

3.5. Nuove annotazioni per l'esecuzione di test

La @RunWith stato utilizzato per integrare contesto prova con altre strutture o per modificare il flusso globale di esecuzione nei casi di prova in JUnit 4.

Con JUnit 5, ora possiamo utilizzare l' annotazione @ExtendWith per fornire funzionalità simili.

Ad esempio, per utilizzare le funzionalità Spring in JUnit 4:

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

Ora, in JUnit 5 è una semplice estensione:

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

3.6. Nuove annotazioni delle regole di test

In JUnit 4, le annotazioni @Rule e @ ClassRule sono state utilizzate per aggiungere funzionalità speciali ai test.

In JUnit 5. possiamo riprodurre la stessa logica utilizzando l' annotazione @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

Come abbiamo visto in questo articolo, JUnit 5 è una versione moderna e modulare del framework JUnit 4. Abbiamo introdotto le principali differenze tra queste due versioni e suggerito come migrare dall'una all'altra.

L'implementazione completa di questo tutorial può essere trovata in oltre su GitHub.