© STEVEN CHIANG/Shutterstock.com
Die Highlights von JUnit 5

Es lebe das Testen


Das Testframework JUnit hat seit dem ersten Release wesentlich dazu beigetragen, testgetriebene Entwicklung voranzubringen. Der Legende nach wurde es ursprünglich im Jahr 1997 von Kent Beck und Erich Gamma im Flugzeug per Pair Programming entwickelt [1] und war seitdem Vorbild für viele andere Testframeworks. Nach langer Entwicklung ist mit JUnit 5 endlich das ersehnte Major-Release erschienen. Wir werfen einen Blick auf die wichtigsten neuen Features.

Im Laufe der Jahre hatte es sich gezeigt, dass die zur Verfügung stehenden Konstrukte von JUnit Erweiterungen erschwerten. Auch die Art und Weise, in der IDEs JUnit integrierten, stellte sich als zunehmend hinderlich für die Weiterentwicklung heraus. Dazu kommt, dass die vorherigen Versionen keine Sprachfeatures von Java 8 unterstützen konnten, weil stets die Kompatibilität zu Java 5 gewahrt bleiben musste. Nach längerer Zeit ohne neue Releases und ohne grundlegende Modernisierungsmöglichkeit hat im Oktober 2015 die Entwicklung der vollständig überarbeiteten Version 5 begonnen. Nach einer Startfinanzierung durch die Crowdfunding-Kampagne JUnit Lambda begann im Oktober 2015 die Planung der neuen Version bei einem Workshop mit dem Core-Committer-Team und Herstellern der Tools Eclipse, Intellij IDEA, Gradle und Spring. Nach einem Prototyp und einer Reihe von Milestone-Releases ist im Sommer 2017 mit Version 5.0.0 GA das erste Produktionsrelease der neuen Version erschienen. Version 5.1 ist bereits in Planung.

Ich stelle einige neue Features der neuen Version 5 vor, die für das Schreiben von Tests und damit für alle Entwickler wichtig sind. Als Einstieg soll ein minimalistisches Beispiel dienen, bevor ich einige fortgeschrittene oder grundsätzlich neue Feature vorstelle. Alles Folgende bezieht sich auf die neue JUnit-Jupiter-Test-Engine. Wie es nahe liegt, heißt die wichtigste Annotation immer noch @Test. Im Unterschied zu JUnit 4 muss man allerdings ein anderes Package importieren: org.junit.jupiter.api anstelle von org.junit. Hierbei bezeichnet jupiter die Test-Engine, die das neue JUnit-5-Programmiermodell unterstützt. Die neue JUnit-Plattform unterstützt die Koexistenz verschiedener Test-Engines.

Listing 1: Hello TestWorld!

@BeforeALL static void setupServer() {} @BeforeEach void prepareDatabase() {} @Test void myTest() {} @AfterEach void cleanupDatabase() {} @AfterALL static void tearDownServer {}

Man erkennt in Listing 1, dass sich die Namen der Lifecycle-Methoden im Vergleich zu JUnit 4 geändert haben. Die neue Nomenklatur ist das Ergebnis langer Diskussionen und versucht, die Bedeutung noch deutlicher hervorzuheben, als es bisher der Fall war [2]. @ BeforeAll wird einmal pro Testklasse aufgerufen, @ BeforeEach vor jeder einzelnen Testmethode. Gleiches gilt für die After-Methoden. Erwähnenswert ist ebenfalls, dass der Modifier public entfallen kann.

Frei definierbare Namen

Die Annotation @DisplayName ermöglicht es, fast beliebige Namen für Testklassen und einzelne Testmethoden zu verwenden, sodass sich übersichtliche und gut lesbare Baumdarstellungen im GUI der IDE aufbauen lassen (Listing 2).

Listing 2: Annotation „@DisplayName“

@DiplayName("HTTP tests for REST product service") public class DisplayNameDemo { @Test @Displayname("GET 'http://localhost:8080/products/4711' user: Bob") public void getProduct() {...} ... @Test @DisplayName("POST 'http://localhost:8080/products/' user:Alice") public void addProduct() {...}

Dies ergibt eine saubere Darstellung in der IDE (Abb. 1). Das Besondere an diesen neuen Features ist die Tatsache, dass die IDE trotzdem noch in der Lage ist, zwischen der Baumansicht und dem Sourcecode zu navigieren. Das wird dadurch ermöglicht, dass die JUnit-Plattform der IDE die Möglichkeit gibt, einzelne Tests sauber zu referenzieren, ohne reflexiv auf den Methodennamen zuzugreifen.

merdes_junit5_1.tif_fmt1.jpgAbb. 1: Ausführung von Tests mit frei definierte Namen

Parameter Injection und Test-Reporting

Eine weitere Neuerung, die vor allem aus dem Spring Framework und anderen Dependency-Injection-Mechanismen bekannt ist, ist die Möglichkeit der Parameter-Injection.

@Test void reporting(TestReporter reporter) { reporter.publishEntry("balance", "47.11"); }

Durften Testmethoden in den bisherigen Versionen von JUnit keine Argumente haben, fällt diese Einschränkung mit JUnit Jupiter weg. Dieser neue Mechanismus ermöglicht es Erweiterungen, Parameter für die Ausführung einer Testmethode bereitzustellen. Dazu können ParameterResolver-Extensions registriert werden, um Parameter aufzulösen, z. B. basierend auf einem bestimmten Typ oder einer bestimmten Annotation. Im Beispiel wird der bereits mitgelieferte typbasierte TestReporterParameterResolver aktiv, um eine TestReporter-Instanz zu liefern. Mit diesem TestReporter können unabhängig von der Konsole Informationen geordnet an die ausführende Umgebung geliefert werden.

Tags und Metaannotationen

Eine weitere Veränderung im Vergleich zu JUnit 4 ist das Tagging von Tests mit bestimmten Labeln, was in JUnit 5 stringbasiert und nicht mehr über den klassenbasierten Category-Mechanismus gelöst ist.

@Test @Tag("fast") public void taggedTest() {...}

Möchte man nun für eine Menge von Tests, z. B. für alle Integrationstests, ein solches Tag vergeben, kann es sinnvoll sein, einen neu eingeführten Mechanismus zu nutzen. So wird nämlich für alle im Jupiter-API vorhandenen Annotationen eine Kombination von Annotationen zu Metaannotationen unterstützt. Ähnliche Mechanismen sind aus dem Spring Framework oder auch aus der Programmiersprache Groovy bekannt.

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Tag("fast") @Test public @interface FastTest { }

Im Beispiel werden besonders schnell ausführbare Tests durch die Metaannotation @FastTest gekennzeichnet, z. B. weil man sie aus Fast-Feedback-Gründen i...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang