Testen mit JUnit 5

Mit Version 5 von JUnit wird das Testen unter Java noch einfacher. Hier ein paar Beispiele …

Eines vorweg, das Testen wird einfacher, die Installation wurde durch die Modularisierung etwas komplizierter. In der JUnit-Dokumentation wird im Abschnitt Installation in einem Diagramm 15 (!) voneinander abhängige Komponenten dargestellt. Auf GitHub gibt es Beispielprojekte für verschiedene Programmiersprachen und Build-Werkzeuge.

Alle Details zu den folgenden Beispiel können in der ausführlichen Dokumentation auf der Webseite von JUnit nachgelesen werden.

Das vollständige Beispiel der nachfolgenden Codeschnipsel liegt bei mir auf GitHub.

Gradle-Konfiguration

Für Gradle und Java sieht die Konfiguration so aus:

plugins {
    id 'java'
}

sourceCompatibility = 11

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.2'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.3.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.2'
}

test {
    useJUnitPlatform()
}

Wie man sieht, sind tatsächlich nicht alle 15 Komponenten wirklich als Abhängigkeit notwendig. Sollen keine datengetriebenen Tests durchgeführt werden, kann auf das Artefakt junit-jupiter-params verzichtet werden.

Für CI-Builds zum Beispiel nützlich, sind hilfreiche Ausgaben auf der Konsole, vor allem bei Fehlern. Diese lassen sich erzeugen mit der testLogging-Erweiterung des Test-Blocks:

test {
    useJUnitPlatform()
    testLogging {
        events 'passed', 'skipped', 'failed'
        exceptionFormat = 'full'
        showStackTraces = false
    }
}

Einfache Tests

Einfache Test sind mit JUnit 4 und 5 gleich:

@Test
void convert() throws ParseException {
    assertEquals(4, RomanConverter.fromRoman("IV"));
}

Lediglich die Pakete der zu importierenden Annotationen und Asserts hat sich geändert.

Datengetriebene Tests

Einfacher geworden sind datengetriebene Tests. Wofür bisher eine eigene Klasse notwendig war, können datengetrieben Test mit JUnit 5 als Methode definiert werden. Die Testparameter werden nun einfach mit einer Annotation festgelegt.

@ParameterizedTest
@CsvSource({
        "M, 1000", // nur eine römische Ziffer
        "XVI, 16", // nur Addition von Ziffernwerten
        "MCDXCII, 1492",
        "MCMLXXXIV, 1984",
})
void fromRomanNumerals(String romanNumeral, int translation) throws ParseException {
    assertEquals(translation, RomanConverter.fromRoman(romanNumeral));
}

Eine Tabelle mit Eingangsdaten und Ausgangsdaten kann als CSV-Daten direkt in die Annotation @CsvSource notiert werden. Die CSV-Daten können auch als Resource im Classpath geladen werden: @CsvFileSource(resources = "/testdaten.csv", numLinesToSkip = 1). Alternativ gibt es weitere Annotationen, zum Beispiel für eine Fabrikmethode eines Streams von Parametern.

Ausnahmeverhalten testen

Statt mit einer Rule, können nun Ausnahmen direkt in der Testmethode geprüft werden. Dafür wird der Testcode in einem Lambda-Ausdruck ausgeführt. Das Assert, das diesen Lambda-Ausdruck ausführt, gibt die geworfene Exception zurück, die dann weiter untersucht werden kann. Wird die erwartete Ausnahme nicht geworfen, schlägt das Assert fehl.

@Test
void notARomanNumeral() {
    ParseException exception = assertThrows(ParseException.class, () -> {
        RomanConverter.fromRoman("XAI");
    });
    assertEquals("not a roman digit: A", exception.getMessage());
    assertEquals(1, exception.getErrorOffset());
}

Benennen von Tests

Da die Testmethoden nicht immer gute Namen abgeben, können für Testprotokolle alternative Namen angegeben werden.

Für allgemeine Tests, wird dafür die Annotation @DisplayName verwendet.

@Test
@DisplayName("XAI is not a roman numeral")
void notARomanNumeral() {
    [...]
}

Für datengetriebene Tests wird die Annotation verwendet.

@ParameterizedTest(name = "[{index}] Convert from roman numeral {0} to {1}")
@CsvSource({ [...] })
void fromRomanNumerals(String romanNumeral, int translation) throws ParseException {
    [...]
}

Das Ergebnis im Testprotokoll von Gradle sieht dann zum Beispiel so aus:

Benannte Tests
Benannte Tests

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert