Java JUnit Unit-Testing-Framework
JUnit ist eines der beliebtesten Unit-Testing-Frameworks für die Programmiersprache Java und wird verwendet, um wiederholbare automatisierte Tests zu schreiben und auszuführen.
JUnit wurde von Kent Beck und Erich Gamma erstellt und ist ein Mitglied der xUnit-Familie. Unit-Testing ist der Prozess des Überprüfens und Verifizierens der kleinsten testbaren Teile von Software, meist Methoden oder Klassen.
Zu den Hauptmerkmalen von JUnit gehören:
- Bietet Annotationen zur Identifizierung von Testmethoden
- Bietet Assertions zur Überprüfung erwarteter Ergebnisse
- Unterstützt Test-Suiten
- Bietet einen Test-Runner
Warum brauchen wir Unit-Testing?
Unit-Testing ist ein unverzichtbarer Bestandteil der modernen Softwareentwicklung. Es bietet die folgenden Vorteile:
- Frühe Problemerkennung: Fehler während der Entwicklung entdecken und beheben
- Verbesserte Codequalität: Ermutigt Entwickler, Code modularer und testbarer zu schreiben
- Dokumentationswert: Testfälle selbst sind die beste Dokumentation des Codeverhaltens
- Sicherheitsnetz für Refactoring: Stellt sicher, dass das Ändern von Code bestehende Funktionalität nicht bricht
- Reduzierte Debugging-Zeit: Probleme schnell lokalisieren
Verwendung von JUnit in Projekten
Für JUnit 5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
Für JUnit 4:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
JUnit 5 Grundlagen
JUnit 5 ist die neueste Version und besteht aus drei Hauptmodulen:
- JUnit Platform (die Grundlage zum Ausführen von Tests)
- JUnit Jupiter (neues Programmiermodell und Erweiterungsmodell)
- JUnit Vintage (unterstützt das Ausführen von JUnit 3- und 4-Tests)
Grundlegende Annotationen
Veraltete Annotationen:
@Test: Markiert eine Methode als Testmethode@Before: Wird vor jeder Testmethode ausgeführt@After: Wird nach jeder Testmethode ausgeführt@BeforeClass: Wird vor allen Tests ausgeführt (statische Methode)@AfterClass: Wird nach allen Tests ausgeführt (statische Methode)@Ignore: Ignoriert eine Testmethode
Beispiel
public class CalculatorTest {
@BeforeClass
public static void setUpBeforeClass() {
System.out.println("Vor allen Tests");
}
@Before
public void setUp() {
System.out.println("Vor jedem Test");
}
@Test
public void testAddition() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
Assert.assertEquals(5, result);
}
@Test
@Ignore("Noch nicht implementiert")
public void testSubtraction() {
// Testcode
}
@After
public void tearDown() {
System.out.println("Nach jedem Test");
}
@AfterClass
public static void tearDownAfterClass() {
System.out.println("Nach allen Tests");
}
}
JUnit 5 ist die Version der nächsten Generation mit den folgenden neuen Annotationen:
@BeforeEachersetzt@Before@AfterEachersetzt@After@BeforeAllersetzt@BeforeClass@AfterAllersetzt@AfterClass@Disabledersetzt@Ignore
Beispiel
@Test
void testMethod() {
// Testcode
}
@BeforeEach
void setUp() {
// Läuft vor jeder Testmethode
}
@AfterEach
void tearDown() {
// Wird nach jeder Testmethode ausgeführt
}
@BeforeAll
static void initAll() {
// Wird einmal vor allen Testmethoden ausgeführt
}
@AfterAll
static void tearDownAll() {
// Wird einmal nach allen Testmethoden ausgeführt
}
Gängige Assertion-Methoden
JUnit bietet eine umfangreiche Sammlung von Assertion-Methoden zur Überprüfung von Testergebnissen:
assertEquals(expected, actual)assertTrue(condition)assertFalse(condition)assertNull(object)assertNotNull(object)assertSame(expected, actual)(Prüft, ob es dasselbe Objekt ist)assertNotSame(unexpected, actual)assertArrayEquals(expectedArray, actualArray)
Beispiel
@Test
void testAssertions() {
// Assertion auf Gleichheit
assertEquals(expected, actual);
// Assertion auf true
assertTrue(condition);
// Assertion auf null
assertNull(object);
// Assertion auf Exception
assertThrows(ExpectedException.class, () -> {
// Code, der eine Exception auslöst
});
// Timeout-Assertion
assertTimeout(Duration.ofMillis(100), () -> {
// Code, der innerhalb der angegebenen Zeit abgeschlossen sein sollte
});
}
Ihren ersten JUnit-Test schreiben
Lernen wir anhand eines einfachen Beispiels, wie man JUnit-Tests schreibt.
1. Die zu testende Klasse erstellen
Beispiel
public int add(int a, int b) {
return a + b;
}
public int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("Divisor cannot be zero");
}
return a / b;
}
}
2. Die Testklasse erstellen
Beispiel
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void testAdd() {
assertEquals(5, calculator.add(2, 3));
}
@Test
void testDivide() {
assertEquals(2, calculator.divide(6, 3));
}
@Test
void testDivideByZero() {
assertThrows(ArithmeticException.class, () -> {
calculator.divide(1, 0);
});
}
}
Erweiterte JUnit-Funktionen
Parametrisierte Tests
JUnit 5 bietet die@ParameterizedTestAnnotation, die es ermöglicht, denselben Test mehrmals mit unterschiedlichen Parametern auszuführen:
Beispiel
@ValueSource(ints = {1, 2, 3})
void testWithValueSource(int argument) {
assertTrue(argument > 0 && argument < 4);
}
Test-Lebenszyklus
Das Verständnis des JUnit-Test-Lebenszyklus ist wichtig, um effektive Tests zu schreiben:
@BeforeAllMethodenausführung (nur einmal)- Für jede Testmethode:
- Eine Instanz der Testklasse erstellen
@BeforeEachMethodenausführung- Testmethodenausführung
@AfterEachMethodenausführung
@AfterAllMethodenausführung (nur einmal)
Test-Suiten
Sie können die@SuiteAnnotation zum Kombinieren mehrerer Testklassen, damit sie zusammen ausgeführt werden:
Beispiel
import org.junit.platform.suite.api.Suite;
@Suite
@SelectClasses({CalculatorTest.class, AnotherTest.class})
public class TestSuite {
}
Best Practices
- Testbenennung: Testmethodennamen sollten ihre Absicht klar ausdrücken, wie z. B.
shouldReturnTrueWhenInputIsValid() - Einzelverantwortung: Jede Testmethode sollte nur eine Funktionalität testen
- Unabhängige Tests: Tests sollten keine Abhängigkeiten voneinander haben
- Schnelles Feedback: Tests schnell laufen lassen
- Testabdeckung: Strebe eine angemessene Abdeckung an, aber verfolge nicht blind 100%
- Testdaten: Aussagekräftige Testdaten verwenden
- Vermeiden Sie das Testen von Implementierungsdetails: Testen Sie Verhalten statt Implementierung
Häufig gestellte Fragen
Was ist der Unterschied zwischen JUnit 4 und JUnit 5?
Die Hauptunterschiede umfassen:
- JUnit 5 erfordert Java 8 oder höher
- Annotationen wurden verschoben von dem
org.junitPaket in dasorg.junit.jupiter.apiPaket @Beforeund@Aftergeändert zu@BeforeEachund@AfterEach@BeforeClassund@AfterClassgeändert zu@BeforeAllund@AfterAll- JUnit 5 führt ein Erweiterungsmodell ein, um die Regeln von JUnit 4 zu ersetzen
Wie führt man JUnit-Tests aus?
Sie können JUnit-Tests auf folgende Weise ausführen:
- Klicken Sie mit der rechten Maustaste auf die Testklasse oder -methode in der IDE und wählen Sie "Run"
- Mit Maven:
mvn test - Mit Gradle:
gradle test - Verwendung des JUnit Console Launchers
Wie testet man private Methoden?
Es wird im Allgemeinen nicht empfohlen, private Methoden direkt zu testen; testen Sie sie stattdessen indirekt über öffentliche Methoden. Wenn Sie private Methoden testen müssen, beachten Sie:
- Verwendung von Reflection
- Ändern Sie die Methode in paketprivat (kein Zugriffsmodifizierer) und erstellen Sie eine Testklasse mit derselben Paketstruktur im Testverzeichnis
- Refaktorieren Sie den Code, um die Logik der privaten Methode in eine separate Klasse auszulagern
Zusammenfassung
JUnit ist ein unverzichtbares Testwerkzeug für Java-Entwickler. Wer es beherrscht, kann die Codequalität und Entwicklungseffizienz erheblich verbessern. Beginnen Sie mit einfachen Unit-Tests und lernen Sie nach und nach fortgeschrittenere Funktionen kennen, wie parametrisierte Tests und Test-Suites. Denken Sie daran, dass gute Tests genauso wertgeschätzt werden sollten wie Produktionscode; ebenso wichtig ist es, den Testcode sauber und wartbar zu halten.
Andere Erweiterungen
Gängige Java-Bibliotheken