23 Unit-Testing mit Maven und JUnit

23.1 Einführung in Unit-Tests mit Maven

Unit-Tests sind ein zentraler Bestandteil der modernen Softwareentwicklung. Sie ermöglichen es, Einzelkomponenten eines Systems isoliert zu testen, um Fehler frühzeitig zu erkennen und die Codequalität sicherzustellen.

Maven bietet mit dem Maven Surefire Plugin eine einfache Möglichkeit, Unit-Tests zu verwalten und in den Build-Prozess zu integrieren. Dabei werden Tests automatisch während der test-Phase ausgeführt.


23.2 Grundlagen von Unit-Tests mit Maven

Maven ist ein Build-Management-Tool, das durch Plugins erweiterbar ist. Standardmäßig nutzt Maven für Unit-Tests JUnit oder TestNG.

23.2.1 Installation und Abhängigkeiten

Damit JUnit 5 in einem Maven-Projekt verwendet werden kann, müssen die folgenden Abhängigkeiten in die pom.xml aufgenommen werden:

<dependencies>
    <!-- JUnit 5 API -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>

    <!-- JUnit 5 Engine für Maven Surefire Plugin -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Die scope=test-Einstellung sorgt dafür, dass diese Abhängigkeiten nur während des Testens verwendet werden.


23.2.2 Erste Unit-Test-Klasse

Eine typische JUnit-Testklasse sieht wie folgt aus:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    @Test
    void testAddition() {
        int result = 2 + 3;
        assertEquals(5, result, "Addition sollte korrekt sein");
    }
}

Hier wird die Methode assertEquals() genutzt, um das erwartete Ergebnis mit dem tatsächlichen zu vergleichen.


23.2.3 Testausführung mit Maven

Sobald die Tests geschrieben sind, können sie mit Maven ausgeführt werden:

mvn test

Dies startet das Maven Surefire Plugin, das automatisch nach Testklassen sucht und diese ausführt.

Spezifische Tests ausführen:

mvn -Dtest=CalculatorTest test

Spezifische Methoden in einer Testklasse ausführen:

mvn -Dtest=CalculatorTest#testAddition test

23.3 Maven Surefire Plugin für Unit-Tests

Das Maven Surefire Plugin ist für die Ausführung von Unit-Tests zuständig. Es ist in Maven bereits integriert, kann aber explizit mit einer bestimmten Version konfiguriert werden:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.0.0-M7</version>
        </plugin>
    </plugins>
</build>

Standardverhalten: - Sucht nach Testklassen im src/test/java/-Verzeichnis. - Führt automatisch alle Klassen aus, die auf *Test.java, Test*.java oder *Tests.java enden. - Erstellt einen Testbericht unter target/surefire-reports/.


23.4 Erweiterte Testkonfiguration

23.4.1 Ausschließen und Einbinden bestimmter Tests

Manchmal sollen nur bestimmte Tests ausgeführt oder ausgeschlossen werden:

<configuration>
    <includes>
        <include>**/*UnitTest.java</include>
    </includes>
    <excludes>
        <exclude>**/*IntegrationTest.java</exclude>
    </excludes>
</configuration>

23.4.2 Fehlerhafte Tests erneut ausführen

Falls manche Tests instabil sind, können fehlgeschlagene Tests automatisch wiederholt werden:

<configuration>
    <rerunFailingTestsCount>2</rerunFailingTestsCount>
</configuration>

23.5 Unterschied zwischen Unit-Tests und Integrationstests

Unit-Tests testen einzelne Methoden oder Klassen isoliert. Integrationstests hingegen überprüfen das Zusammenspiel mehrerer Komponenten, z. B. eine Datenbankanbindung.

Für Integrationstests wird das Maven Failsafe Plugin genutzt:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.0.0-M7</version>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Testklassen sollten dann mit *IT.java benannt werden, um von Failsafe erkannt zu werden.


23.6 JUnit 5 Erweiterungen

JUnit 5 bietet weitere Features für fortgeschrittene Tests:

23.6.1 Parameterisierte Tests

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class ParameterizedExampleTest {

    @ParameterizedTest
    @ValueSource(ints = {1, 2, 3, 4})
    void testMultipleValues(int value) {
        assertTrue(value > 0);
    }
}

23.6.2 Lifecycle-Callbacks

JUnit 5 erlaubt spezielle Methoden für Setup und Teardown:

import org.junit.jupiter.api.*;

class LifecycleTest {

    @BeforeAll
    static void setup() { System.out.println("Vor allen Tests"); }

    @BeforeEach
    void init() { System.out.println("Vor jedem Test"); }

    @Test
    void test1() { System.out.println("Test 1 läuft"); }

    @Test
    void test2() { System.out.println("Test 2 läuft"); }

    @AfterEach
    void cleanup() { System.out.println("Nach jedem Test"); }

    @AfterAll
    static void teardown() { System.out.println("Nach allen Tests"); }
}

23.6.3 Weiterführende Informationen