Java JUnit Unit-Testing-Framework

Java 常用类库Gängige Java-Bibliotheken


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:

  1. Frühe Problemerkennung: Fehler während der Entwicklung entdecken und beheben
  2. Verbesserte Codequalität: Ermutigt Entwickler, Code modularer und testbarer zu schreiben
  3. Dokumentationswert: Testfälle selbst sind die beste Dokumentation des Codeverhaltens
  4. Sicherheitsnetz für Refactoring: Stellt sicher, dass das Ändern von Code bestehende Funktionalität nicht bricht
  5. 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

import org.junit.*;

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

import org.junit.jupiter.api.*;

@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

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

@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 class Calculator {
    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 org.junit.jupiter.api.*;
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

@ParameterizedTest
@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:

  1. @BeforeAllMethodenausführung (nur einmal)
  2. Für jede Testmethode:
    • Eine Instanz der Testklasse erstellen
    • @BeforeEachMethodenausführung
    • Testmethodenausführung
    • @AfterEachMethodenausführung
  3. @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.SelectClasses;
import org.junit.platform.suite.api.Suite;

@Suite
@SelectClasses({CalculatorTest.class, AnotherTest.class})
public class TestSuite {
}

Best Practices

  1. Testbenennung: Testmethodennamen sollten ihre Absicht klar ausdrücken, wie z. B.shouldReturnTrueWhenInputIsValid()
  2. Einzelverantwortung: Jede Testmethode sollte nur eine Funktionalität testen
  3. Unabhängige Tests: Tests sollten keine Abhängigkeiten voneinander haben
  4. Schnelles Feedback: Tests schnell laufen lassen
  5. Testabdeckung: Strebe eine angemessene Abdeckung an, aber verfolge nicht blind 100%
  6. Testdaten: Aussagekräftige Testdaten verwenden
  7. 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 demorg.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:

  1. Klicken Sie mit der rechten Maustaste auf die Testklasse oder -methode in der IDE und wählen Sie "Run"
  2. Mit Maven:mvn test
  3. Mit Gradle:gradle test
  4. 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:

  1. Verwendung von Reflection
  2. Ändern Sie die Methode in paketprivat (kein Zugriffsmodifizierer) und erstellen Sie eine Testklasse mit derselben Paketstruktur im Testverzeichnis
  3. 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.

Java 常用类库Gängige Java-Bibliotheken

Andere Erweiterungen