Testen in Java: Unit, Integration, E2E von A bis Z

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum Testing das Fundament qualitativ hochwertigen Java-Codes ist

Jeder Java-Entwickler kennt die Situation, dass nach der Behebung eines Bugs drei neue auftauchen. Um diesen Teufelskreis zu durchbrechen, gibt es Testing. Es ist nicht nur ein Häkchen auf einer Checkliste, sondern eine professionelle Disziplin, die Nerven, Geld und den Ruf des Produkts schützt.

In diesem Artikel analysieren wir drei entscheidende Testebenen: Unit-Tests, Integrationstests und E2E-Tests (End-to-End). Wir betrachten sie anhand praktischer Java-Beispiele unter Verwendung gängiger Frameworks: JUnit 5, Mockito, Spring Boot Test und Selenium. Sie erfahren, wie Sie eine richtige Testpyramide aufbauen und Ihr Projekt nicht mit nutzlosen Tests überlasten.



1. Unit-Testing: Überprüfung atomarer Code-Einheiten

Unit-Tests sind die unterste und schnellste Ebene. Sie überprüfen die Arbeit einer einzelnen "Unit" (normalerweise einer Methode oder Klasse) isoliert von externen Abhängigkeiten (DB, API, Dateisystem).



1.1 Werkzeuge und Frameworks

  • JUnit 5 — der De-facto-Standard zum Schreiben von Tests in Java.
  • Mockito — eine Bibliothek zum Erstellen von Platzhaltern (Mocks) und Stubs.
  • AssertJ — eine Bibliothek für fließende Überprüfungen (Assertions).


1.2 Beispiel eines Unit-Tests mit JUnit 5 und Mockito

Stellen wir uns vor, wir haben einen Service OrderService, der von einem Repository PaymentRepository abhängt. Wir möchten die Logik des Services testen, ohne die echte Datenbank aufzurufen.

// Zu testende Klassepublic class OrderService {    private final PaymentRepository paymentRepository;

public OrderService(PaymentRepository paymentRepository) { this.paymentRepository = paymentRepository; }

public String processOrder(Order order) { if (order.getAmount() <= 0) { throw new IllegalArgumentException("Der Bestellbetrag muss positiv sein"); } boolean success = paymentRepository.pay(order); return success ? "Erfolgreich bezahlt" : "Zahlungsfehler"; }}

// Unit-Testimport org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.junit.jupiter.MockitoExtension;import static org.junit.jupiter.api.Assertions.*;import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)class OrderServiceTest {

@Mock private PaymentRepository paymentRepository;

@InjectMocks private OrderService orderService;

@Test void testProcessOrder_Success() { // Arrange Order order = new Order(100.0); when(paymentRepository.pay(order)).thenReturn(true);

// Act String result = orderService.processOrder(order);

// Assert assertEquals("Erfolgreich bezahlt", result); verify(paymentRepository, times(1)).pay(order); }

@Test void testProcessOrder_NegativeAmount() { // Arrange Order order = new Order(-10.0);

// Act & Assert assertThrows(IllegalArgumentException.class, () -> { orderService.processOrder(order); }); }}

Best Practices für Unit-Tests:

  • Ein Test – eine Überprüfung (FIRST-Prinzip: Fast, Isolated, Repeatable, Self-validating, Timely).
  • Verwenden Sie verständliche Namen: shouldReturnSuccess_whenPaymentIsApproved.
  • Testen Sie keine private-Methoden – testen Sie den öffentlichen Vertrag.
  • Decken Sie Grenzfälle ab: null, leere Strings, negative Zahlen.


2. Integrationstesting: Überprüfung der Interaktion von Komponenten

Integrationstests überprüfen, wie verschiedene Module des Systems

Blogs

Buchempfehlungen