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.
Maven ist ein Build-Management-Tool, das durch Plugins erweiterbar ist. Standardmäßig nutzt Maven für Unit-Tests JUnit oder TestNG.
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.
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.
Sobald die Tests geschrieben sind, können sie mit Maven ausgeführt werden:
mvn testDies startet das Maven Surefire Plugin, das automatisch nach Testklassen sucht und diese ausführt.
Spezifische Tests ausführen:
mvn -Dtest=CalculatorTest testSpezifische Methoden in einer Testklasse ausführen:
mvn -Dtest=CalculatorTest#testAddition testDas 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/.
Manchmal sollen nur bestimmte Tests ausgeführt oder ausgeschlossen werden:
<configuration>
<includes>
<include>**/*UnitTest.java</include>
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
</excludes>
</configuration>Falls manche Tests instabil sind, können fehlgeschlagene Tests automatisch wiederholt werden:
<configuration>
<rerunFailingTestsCount>2</rerunFailingTestsCount>
</configuration>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.
JUnit 5 bietet weitere Features für fortgeschrittene 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);
}
}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"); }
}