Een gids voor JUnit 5

1. Overzicht

JUnit is een van de meest populaire frameworks voor unit-testing in het Java-ecosysteem. De JUnit 5-versie bevat een aantal opwindende innovaties, met het doel om nieuwe functies in Java 8 en hoger te ondersteunen, en maken veel verschillende teststijlen mogelijk.

2. Maven afhankelijkheden

Het opzetten van JUnit 5.x.0 is vrij eenvoudig, we moeten de volgende afhankelijkheid toevoegen aan onze pom.xml:

 org.junit.jupiter junit-jupiter-engine 5.1.0 test 

Het is belangrijk op te merken dat deze versie vereist dat Java 8 werkt.

Bovendien is er nu directe ondersteuning om Unit-tests uit te voeren op het JUnit-platform in Eclipse en IntelliJ. U kunt natuurlijk ook tests uitvoeren met het doel van Maven Test.

Aan de andere kant ondersteunt IntelliJ standaard JUnit 5. Daarom is het uitvoeren van JUnit 5 op IntelliJ vrij eenvoudig: klik met de rechtermuisknop -> Uitvoeren of Ctrl-Shift-F10.

3. Architectuur

JUnit 5 is samengesteld uit verschillende modules van drie verschillende subprojecten:

3.1. JUnit-platform

Het platform is verantwoordelijk voor het lanceren van testframeworks op de JVM. Het definieert een stabiele en krachtige interface tussen JUnit en zijn client, zoals build-tools.

Het uiteindelijke doel is hoe zijn klanten gemakkelijk kunnen worden geïntegreerd met JUnit bij het ontdekken en uitvoeren van de tests.

Het definieert ook de TestEngine API voor het ontwikkelen van een testraamwerk dat op het JUnit-platform draait. Op die manier kunt u testbibliotheken van derden rechtstreeks in JUnit pluggen door aangepaste TestEngine te implementeren.

3.2. JUnit Jupiter

Deze module bevat nieuwe programmeer- en uitbreidingsmodellen voor het schrijven van tests in JUnit 5. Nieuwe annotaties in vergelijking met JUnit 4 zijn:

  • @TestFactory - geeft een methode aan die een testfabriek is voor dynamische tests
  • @Weergavenaam - definieert een aangepaste weergavenaam voor een testklasse of een testmethode
  • @Genest - geeft aan dat de geannoteerde klasse een geneste, niet-statische testklasse is
  • @Label - declareert tags voor filtertests
  • @ExtendWith - het wordt gebruikt om aangepaste extensies te registreren
  • @BeforeEach - geeft aan dat de geannoteerde methode wordt uitgevoerd vóór elke testmethode (voorheen @Voordat)
  • @Na elke - geeft aan dat de geannoteerde methode wordt uitgevoerd na elke testmethode (voorheen @Na)
  • @Voor alles - geeft aan dat de geannoteerde methode wordt uitgevoerd vóór alle testmethoden in de huidige klasse (voorheen @Voor klas)
  • @Ten slotte - geeft aan dat de geannoteerde methode wordt uitgevoerd na alle testmethoden in de huidige klasse (voorheen @Na de les)
  • @Uitschakelen - het wordt gebruikt om een ‚Äč‚Äčtestklasse of -methode uit te schakelen (voorheen @Negeren)

3.3. JUnit Vintage

Ondersteunt het uitvoeren van op JUnit 3 en JUnit 4 gebaseerde tests op het JUnit 5-platform.

4. Basisaantekeningen

Om nieuwe annotaties te bespreken, hebben we de sectie onderverdeeld in de volgende groepen, verantwoordelijk voor de uitvoering: vóór de tests, tijdens de tests (optioneel) en na de tests:

4.1. @Voor alles en @BeforeEach

Hieronder ziet u een voorbeeld van de eenvoudige code die moet worden uitgevoerd vóór de belangrijkste testgevallen:

@BeforeAll static void setup () {log.info ("@ BeforeAll - voert één keer uit voor alle testmethoden in deze klasse"); } @BeforeEach void init () {log.info ("@ BeforeEach - wordt uitgevoerd vóór elke testmethode in deze klasse"); }

Belangrijk om op te merken is dat de methode met @Voor alles annotatie moet statisch zijn, anders compileert de code niet.

4.2. @Weergavenaam en @Gehandicapt

Laten we naar nieuwe test-optionele methoden gaan:

@DisplayName ("Enkele test succesvol") @Test ongeldig testSingleSuccessTest () {log.info ("Succes"); } @Test @Disabled ("Nog niet geïmplementeerd") ongeldig testShowSomething () {}

Zoals we kunnen zien, kunnen we de weergavenaam wijzigen of de methode uitschakelen met een opmerking, met behulp van nieuwe annotaties.

4.3. @Na elke en @Ten slotte

Laten we tot slot de methoden bespreken die verband houden met bewerkingen na het uitvoeren van tests:

@AfterEach void tearDown () {log.info ("@ AfterEach - uitgevoerd na elke testmethode."); } @AfterAll static void done () {log.info ("@ AfterAll - uitgevoerd na alle testmethoden."); }

Houd er rekening mee dat de methode met @Ten slotte moet ook een statische methode zijn.

5. Beweringen en veronderstellingen

JUnit 5 probeert volledig te profiteren van de nieuwe functies van Java 8, met name lambda-expressies.

5.1. Beweringen

Beweringen zijn verplaatst naar org.junit.jupiter.api.Assertions en zijn aanzienlijk verbeterd. Zoals eerder vermeld, kun je nu lambda's gebruiken in beweringen:

@Test void lambdaExpressions () {assertTrue (Stream.of (1, 2, 3) .stream () .mapToInt (i -> i) .sum ()> 5, () -> "Som moet groter zijn dan 5" ); }

Hoewel het bovenstaande voorbeeld triviaal is, is een voordeel van het gebruik van de lambda-uitdrukking voor het beweringsbericht dat het lui wordt geëvalueerd, wat tijd en middelen kan besparen als de berichtconstructie duur is.

Het is nu ook mogelijk om beweringen te groeperen met assertAll () die alle mislukte beweringen binnen de groep rapporteert met een MultipleFailuresError:

 @Test void groupAssertions () {int [] getallen = {0, 1, 2, 3, 4}; assertAll ("getallen", () -> assertEquals (getallen [0], 1), () -> assertEquals (getallen [3], 3), () -> assertEquals (getallen [4], 1)); }

Dit betekent dat het nu veiliger is om complexere beweringen te doen, omdat u de exacte locatie van een storing kunt bepalen.

5.2. Veronderstellingen

Veronderstellingen worden alleen gebruikt om tests uit te voeren als aan bepaalde voorwaarden is voldaan. Dit wordt meestal gebruikt voor externe omstandigheden die nodig zijn om de test correct te laten verlopen, maar die niet direct verband houden met wat er wordt getest.

Met een aanname kunt u een aanname aangeven aannemenTrue (), aannemenFalse (), en in de veronderstelling dat().

@Test void trueAssumption () {aannemenTrue (5> 1); assertEquals (5 + 2, 7); } @Test void falseAssumption () {aannemenFalse (5 assertEquals (2 + 2, 4)); }

Als een aanname mislukt, a TestAbortedException wordt gegooid en de test wordt gewoon overgeslagen.

Veronderstellingen begrijpen ook lambda-uitdrukkingen.

6. Uitzonderingstesten

Er zijn twee manieren om uitzonderingen te testen in JUnit 5. Beide kunnen worden geïmplementeerd met behulp van assertThrows () methode:

@Test void shouldThrowException () {Throwable exception = assertThrows (UnsupportedOperationException.class, () -> {throw new UnsupportedOperationException ("Niet ondersteund");}); assertEquals (exception.getMessage (), "Niet ondersteund"); } @Test void assertThrowsException () {String str = null; assertThrows (IllegalArgumentException.class, () -> {Integer.valueOf (str);}); }

Het eerste voorbeeld wordt gebruikt om meer details van de gegenereerde uitzondering te verifiëren en het tweede valideert alleen het type uitzondering.

7. Testsuites

Om de nieuwe functies van JUnit 5 voort te zetten, zullen we proberen het concept van het samenvoegen van meerdere testklassen in een testsuite te leren kennen, zodat we deze samen kunnen uitvoeren. JUnit 5 biedt twee annotaties: @SelectPackages en @SelectClasses om testsuites te maken.

Houd er rekening mee dat in dit vroege stadium de meeste IDE's deze functies niet ondersteunen.

Laten we de eerste eens bekijken:

@RunWith (JUnitPlatform.class) @SelectPackages ("com.baeldung") openbare klasse AllUnitTest {}

@SelectPackage wordt gebruikt om de namen op te geven van pakketten die moeten worden geselecteerd bij het uitvoeren van een testsuite. In ons voorbeeld worden alle tests uitgevoerd. De tweede annotatie, @SelectClasses, wordt gebruikt om de klassen te specificeren die moeten worden geselecteerd bij het uitvoeren van een testsuite:

@RunWith (JUnitPlatform.class) @SelectClasses ({AssertionTest.class, AssumptionTest.class, ExceptionTest.class}) openbare klasse AllUnitTest {}

Bovenstaande klasse zal bijvoorbeeld een suite maken die drie testklassen bevat. Houd er rekening mee dat de lessen niet in één pakket hoeven te zitten.

8. Dynamische tests

Het laatste onderwerp dat we willen introduceren, is de functie JUnit 5 Dynamic Tests, waarmee tijdens runtime gegenereerde testcases kunnen worden gedeclareerd en uitgevoerd. In tegenstelling tot de Static Tests die een vast aantal testcases tijdens het compileren definiëren, stellen de Dynamic Tests ons in staat om de testcase dynamisch in de runtime te definiëren.

Dynamische tests kunnen worden gegenereerd door een fabrieksmethode die is geannoteerd met @TestFactory. Laten we eens kijken naar het codevoorbeeld:

@TestFactory openbare stroom translateDynamicTestsFromStream () {terug in.stream () .map (woord -> DynamicTest.dynamicTest ("Test vertalen" + woord, () -> {int id = in.indexOf (woord); assertEquals (uit. get (id), translate (word));})); }

Dit voorbeeld is heel eenvoudig en gemakkelijk te begrijpen. We willen woorden vertalen met twee ArrayList, genaamd in en uit, respectievelijk. De fabrieksmethode moet een Stroom, Verzameling, Herhaalbaar, of Iterator. In ons geval kiezen we voor Java 8 Stroom.

Houd er rekening mee dat @TestFactory methoden mogen niet privé of statisch zijn. Het aantal tests is dynamisch en hangt af van de ArrayList grootte.

9. Conclusie

Het artikel was een snel overzicht van de veranderingen die met JUnit 5 komen.

We kunnen zien dat JUnit 5 een grote verandering in de architectuur heeft die betrekking heeft op platformstarter, integratie met buildtool, IDE, andere Unit-testframeworks, enz. Bovendien is JUnit 5 meer geïntegreerd met Java 8, vooral met Lambdas- en Stream-concepten .

De voorbeelden die in dit artikel worden gebruikt, zijn te vinden in het GitHub-project.