EMZETT.
Login

Kurz: Klassen werden in Paketen (packages) organisiert. Der Paketname entspricht dem Ordnerpfad und steht am Dateianfang:

Teil des Kurses Java

Kapitel 20 von 22 im Kurs Java (Abschnitt „Projekte“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Pakete

Klassen werden in Paketen (packages) organisiert. Der Paketname entspricht dem Ordnerpfad und steht am Dateianfang:

src/main/java/de/meinefirma/shop/Warenkorb.java
 
package de.meinefirma.shop;
 
import java.util.List;
import de.meinefirma.shop.modell.Artikel;
 
public class Warenkorb { ... }
  • Namen schreibt man klein, meist umgekehrte Domain: de.emzett.kurs
  • import macht Klassen aus anderen Paketen verfügbar; java.lang ist immer da
  • import static importiert statische Member (import static java.lang.Math.*;)
  • Ohne Modifikator ist ein Member nur im selben Paket sichtbar (package-private)

Maven und Gradle

Größere Projekte nutzen ein Build-Werkzeug für Abhängigkeiten, Übersetzen, Tests und Pakete:

MavenGradle
Konfigurationpom.xml (XML)build.gradle / build.gradle.kts
Stildeklarativ, standardisiertflexibel, skriptbar
Befehlemvn compile, mvn test, mvn packagegradle build, gradle test

Standardstruktur (bei beiden gleich):

mein-projekt/
├─ pom.xml
├─ src/
│  ├─ main/java/        Produktionscode
│  ├─ main/resources/   Konfiguration, Dateien
│  └─ test/java/        Tests
└─ target/              erzeugte Dateien (nicht ins Repository)

Eine Abhängigkeit in der pom.xml:

<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>5.10.2</version>
  <scope>test</scope>
</dependency>

Bibliotheken kommen aus Maven Central (central.sonatype.com). Die Koordinaten sind groupId:artifactId:version.

Automatische Tests mit JUnit

JUnit 5 ist das Standard-Testframework. Tests sind Methoden mit @Test:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
 
class RechnerTest {
    @Test
    void addiertZahlen() {
        assertEquals(5, Rechner.addiere(2, 3));
    }
 
    @Test
    void teilenDurchNullWirftFehler() {
        assertThrows(ArithmeticException.class, () -> Rechner.teile(1, 0));
    }
 
    @ParameterizedTest
    @CsvSource({"2,3,5", "0,0,0", "-1,1,0"})
    void addiertViele(int a, int b, int erwartet) {
        assertEquals(erwartet, Rechner.addiere(a, b));
    }
}
Annotation / MethodeZweck
@Testmarkiert einen Test
@BeforeEach, @AfterEachVorbereitung/Aufräumen je Test
@ParameterizedTestderselbe Test mit mehreren Eingaben
assertEquals(erwartet, ist)Gleichheit
assertTrue, assertNull, assertNotNullBedingungen
assertThrows(Typ, () -> ...)erwartet eine Ausnahme
assertAll(...)mehrere Prüfungen zusammen

Ohne Bibliothek kannst du die Idee selbst durchspielen:

public class MiniTest {
    static int addiere(int a, int b) { return a + b; }
    static boolean istPalindrom(String s) {
        String t = s.toLowerCase().replaceAll("[^a-z0-9]", "");
        return new StringBuilder(t).reverse().toString().equals(t);
    }
 
    static int fehlgeschlagen = 0;
    static void pruefe(String name, Object erwartet, Object ist) {
        boolean ok = erwartet.equals(ist);
        if (!ok) fehlgeschlagen++;
        System.out.println((ok ? "OK      " : "FEHLER  ") + name);
    }
 
    public static void main(String[] args) {
        pruefe("addiere positiv", 5, addiere(2, 3));
        pruefe("addiere negativ", -1, addiere(2, -3));
        pruefe("Palindrom Anna", true, istPalindrom("Anna"));
        pruefe("Kein Palindrom", false, istPalindrom("Hallo"));
        pruefe("leerer Text", true, istPalindrom(""));
        System.out.println(fehlgeschlagen + " Fehler");
    }
}

Ausgabe:

OK      addiere positiv
OK      addiere negativ
OK      Palindrom Anna
OK      Kein Palindrom
OK      leerer Text
0 Fehler

Aufbau eines guten Tests

Arrange – Act – Assert: Daten vorbereiten, ausführen, Ergebnis prüfen. Gute Tests sind klein, unabhängig voneinander, schnell und sprechend benannt. Teste normale Fälle, Grenzfälle (leer, 0, negativ, sehr groß, null) und Fehlerfälle. Jeden gefundenen Fehler hältst du als Test fest.

Mocking

Wenn Code von Datenbank, Netzwerk oder Uhrzeit abhängt, ersetzt man diese Teile im Test durch Attrappen (Mocks), etwa mit Mockito. Einfacher: Abhängigkeiten über Interfaces und Konstruktor hereingeben (Dependency Injection), dann reicht im Test eine kleine eigene Implementierung.

Weitere Werkzeuge

WerkzeugZweck
Spring BootFramework für Webanwendungen und Dienste
Hibernate / JPAObjekte in Datenbanktabellen abbilden
Jackson / GsonJSON
SLF4J + LogbackLogging statt System.out
Lombokweniger Boilerplate (Records erledigen vieles schon)
Checkstyle, SpotBugs, SonarQubeQualitätsprüfung
JShellinteraktive Konsole zum Ausprobieren (jshell)

Merke

  • Pakete spiegeln die Ordnerstruktur; import holt Klassen aus anderen Paketen
  • Maven und Gradle verwalten Abhängigkeiten, Build und Tests (Standardstruktur src/main und src/test)
  • JUnit 5: @Test, assertEquals, assertThrows
  • Arrange – Act – Assert; Grenz- und Fehlerfälle testen
  • Abhängigkeiten über Interfaces hereingeben, damit sie sich ersetzen lassen

Übungsaufgabe

Lege mit Maven ein Projekt an (mvn archetype:generate), schreibe eine Klasse mit zwei Methoden und mindestens vier JUnit-Tests.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Threads und Nebenläufigkeit

Weiter: Sauberer Java-Code und häufige Fehler

Alle Kapitel: Java im Überblick